Advanced Python for Data Science¶

MSc Artificial Intelligence & Business Analytics,
Toulouse Business School

Objectives¶

Acquiring the Python tools necessary to design a data product MVP in order to quickly test a business opportunity

  • Streamlit, a framework allowing to turn data script into shareable web app in minutes
  • sqlalchemy, A Python SQL toolkit.
  • requests, an elegant and simple HTTP library.

Part #1¶

Objectives of the Part:

  1. Setup the developping environment
  2. Get our first data app up and running

Environment setup¶

Folder organisation and data download¶

> mkdir advanced_python
> cd advanced_python
> mkdir streamlit_apps
> mkdir data
> cd data
# copy data and source code from Campus
> cd ..

Check version of Python and pip¶

Should resp. be 3.6+ and 20.0+

# checking version of Python and pip. Should resp. be 3.6+ and 20.0+
> python --version
> pip --version

Installing the libraries¶

# Streamlit

# Command to run in a Terminal:
> pip install streamlit
> pip install pandas matplotlib seaborn

# to run in Jupyter cell only!
> !pip install streamlit
> !pip install pandas matplotlib seaborn
# requests

# In a Terminal
> pip install requests


# In Jupyter
> !pip install requests
# sqlalchemy

# In a Terminal
> pip install SQLAlchemy

# In Jupyter
>!pip install SQLAlchemy

Streamlit¶

Streamlit is a Python library that turns data scripts into shareable web apps in minutes.
No HTML, CSS, Javascript experience required.

Hello World!¶

import streamlit as st

st.write(
    """
    # My first app
    Hello *World*!
    """
)
''' Streamlit Hello World application

Author: <FirstName> <LastName>
Version: v1.0
'''
# Build-in Libraries

# Third-party Libraries
import streamlit as st

# Custom Libraries


def main():
    '''Streamlit main function
    
    '''
    st.write(
        """
        # My first app
        Hello *World*!
        """
    )

if __name__ == '__main__':
    main()

First app -- load data¶

st.write(
    """
    # My first app
    Tweet sentiment!
    """
)
df_tweet = pd.read_csv('../../data/tweet-sentiment-withDay.csv')

st.write(df_tweet)

An error occurs. Introduce topic of debugging streamlit apps.

  • CSV error solution: encoding="ISO-8859-1"
  • runtime error solution: write only first 10 lines df[:10]

Debugging Streamlit apps¶

We have two solutions for debugging our apps:

  • Develop in Streamlit and use st.write() as a debugger (similar to using print() in a regular Python script)
  • Explore in Jupyter and then copy to Streamlit

Solution #1:

Pros:

  • What you see is what you get
  • No need to maintain both IPython and Python versions of the same app
  • Better experience for learning how to write production code

Cons:

  • A slower feedback loop (the entire app must run before feedback)
  • A potentially unfamiliar development environment

Solution #2:

Pros:

  • The lightning-fast feedback loop makes it easier to experiment.
  • Users may be more familiar with Jupyter.
  • The full app does not have to be run to get results.

Cons:

  • Jupyter may provide deceptive results if run out of order.
  • 'Copying' code over from Jupyter is time-consuming.
  • Python versioning may be different between Jupyter and Streamlit.

Go for solution #1 and use solution #2 only in last resort!

Exercice¶

  1. Put the part of the script loading the data into a separate function.
  • Talk about Flow control in Streamlit

Data manipulation and user input¶

Streamlit has several features allowing user to interact with our app.

https://docs.streamlit.io/library/api-reference/widgets

Let's go and add a selectboxto our app:

users_list = get_users(df_tweet)

selected_user = st.selectbox('Choose a user', users_list)

st.write(f'You selected {selected_user}')

Notes: There are 659775 users, make sure to show only part of it for performances

Exercice¶

  1. Only display the data related to the selected user
  2. Add the option to select all users

Introduction to caching in Streamlit¶

@st.cache
def some_function():
    some commands

As we create more computationally intensive Streamlit apps and begin to use and upload larger datasets, we should start worrying about the runtime of these apps and work to increase our efficiency whenever possible. The easiest way to make a Streamlit app more efficient is through caching, which is storing some results in memory so that the app does not repeat the same work whenever possible.

Plot data¶

Streamlit charts documentation: https://docs.streamlit.io/library/api-reference/charts

  • chart comparison: https://share.streamlit.io/discdiver/data-viz-streamlit/main/app.py

Exercice¶

  1. Plot the number of message tweeted per day
  2. Make the graph to show only data from a given user
In [ ]:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import datetime
df = pd.read_csv('../data/tweet-sentiment-withDay.csv')
df['day_utc'] = pd.to_datetime(df['day_utc'],  infer_datetime_format=True)

df_timeline = df.groupby('day_utc').count()['target'].reset_index()

fig, ax = plt.subplots()
ax = sns.scatterplot(x = 'day_utc', y = 'target', data=df_timeline)
plt.xlabel('day')
plt.xticks(rotation=45)
plt.xlim(df_timeline['day_utc'].min()-datetime.timedelta(days=1), df_timeline['day_utc'].max()+datetime.timedelta(days=1))
plt.ylabel('number of tweets')
plt.title("Timeline of number of tweets")
plt.show()

Solution

import matplotlib.pyplot as plt
import seaborn as sns

# groupby day
df_timeline = df_tweet.groupby('day_utc').count()['target'].reset_index()

# plot
fig, ax = plt.subplots()
ax = sns.lineplot(x = 'day_utc', y = 'target', data=df_timeline)
plt.xlabel('day')
plt.ylabel('number of tweets')
plt.title("Timeline of number of tweets")
st.pyplot(fig)

Pretty App¶

Streamlit Text elements documentation: https://docs.streamlit.io/library/api-reference/text

Exercice¶

  1. Add a title, header and subheader to the app
st.title("Advanced Python for Data Science")
st.header("My First app")
st.subheader("A tweet sentiment analysis")

Finish the day with:

  • presenting the gallery
    • map: https://share.streamlit.io/streamlit/demo-uber-nyc-pickups/
    • complete app: https://share.streamlit.io/jkanner/streamlit-dataview/master/app.py/+/

Part #2¶

Objectives of the day:

  • CODING BEST PRACTICES
    • Clean and modular programming
    • Refactor code
    • Documentation
    • Auto-pep8 and lint
  • UNDERSTAND PYTHON ERROR MESSAGES
  • HOW TO USE MODULE DOCUMENTATION
  • DATA APP
    • add plot
    • add text
    • load data a database
      • presentation of SQLAlchemy
    • introduction to columns and sidebar

Coding best practices¶

There are 5 topics related to coding best practices:

  1. Writing clean and modular code
  2. Refactoring code
  3. Optimizing code to be more efficient (not covered during this course)
  4. Writing documentation
  5. Following PEP8 & Linting

Clean and modular code¶

Clean code -- Code that is readable, simple, and concise. Clean production-quality code is crucial for collaboration and maintainability in software development.

Modular code -- Code that is logically broken up into functions and modules. Modular production-quality code that makes your code more organized, efficient, and reusable.

Module -- A file. Modules allow code to be reused by encapsulating them into files that can be imported into other files.

PEP 8¶

PEP 8 (for Python Extension Proposal) is a set of rules that allows code to be homogenized and best practices to be applied.

Example:

  • Should we indent code by 4 spaces or tabs? --> PEP 8 says that indentation is 4 spaces.
  • Modules should be imported at the beginning of a script
  • Should I use CamelCase or snake_case for naming my functions and variables?

PEP-8: https://www.python.org/dev/peps/pep-0008/

Clean code¶

Writing Clean Code: Meaningful Names¶

  • Be descriptive and imply type:

has_ and is_ are good prefix for booleans.

  • Be consistent but clearly differentiate
  • Avoid abbreviations and single letters
  • Long names aren't the same as descriptive names
In [ ]:
user_list = [1, 2, 3]

for user in user_list:
    print(user)
In [ ]:
# Naming convention

# == Function ==
def good_function_name():
    pass

def BadFunctionNaMe():
    pass
In [ ]:
# == Variables ==
MY_CONSTANT = 42
my_variable = MY_CONSTANT+2
In [ ]:
my_list = [1, 2, 3, 4, 5] # good
my_list = [1,2,3,4,5] # bad
my_list = [1 , 2, 3, 4, 5 ] #bad


my_dict = {
    'key1': 'value1',
    'key2': 42
}
In [ ]:
is_boolean = True
has_boolean = False

is_processed = True
In [ ]:
for element in my_list:
    print(element)
    
# bad naming
for i in lst:
    print(i)
In [ ]:
# == Classes ==
class GoodClassName:
    def __init__(self):
        self.params = 'foo'

class bad_function_name:
    def __init__(self):
        self.params = 'foo'
        
        
        
my_var1 = 42
var     = 32

my_var1 = my_function(arg1, arg2,
                      arg3, arg4)
var = 32 + 42 \
    + 52

Writing Clean Code: Nice Whitespace¶

Use whitespace properly.

  • Organize your code with consistent indentation: the standard is to use four spaces for each indent. You can make this a default in your text editor.
  • Separate sections with blank lines to keep your code well organized and readable.
  • Try to limit your lines to around 79 characters, which is the guideline given in the PEP 8 style guide. In many good text editors, there is a setting to display a subtle line that indicates where the 79 character limit is.
In [ ]:
# Whitespace usage

# == Operator has whitespace before and after ==

# Good coding practices:
my_variable = 3 + 7
my_text = "mouse"
my_text == my_variable

# Bad coding practices:
my_variable=3+7
my_text="mouse"
my_text== my_variable
In [ ]:
# == No whitespace inside (), {}, and [] ==

# Good coding practices:
my_liste[1]
my_dict{"key": 'value'}
my_function(arg)

# Bad coding practices:
my_list[ 1 ]
my_dict{"clé": 'value' }
my_function( arg )

More details¶

Check out the PEP 8 guidelines for code layout

Pop quiz¶

1. Which of the following describes code that is clean? Select all the answers that apply.

  • Repetitive
  • Simple
  • Readable
  • Vague
  • Concise

Pop quiz -- Answers¶

1. Which of the following describes code that is clean? Select all the answers that apply.

  • Repetitive
  • Simple
  • Readable
  • Vague
  • Concise

Modular code¶

Writing Modular Code: DRY¶

Don't repeat yourself!

Modularization allows you to reuse parts of your code. Generalize and consolidate repeated code in functions or loops.

Writing Modular Code: Abstract out logic to improve readability¶

Abstracting out code into a function not only makes it less repetitive, but also improves readability with descriptive function names.

Writing Modular Code: Functions should do one thing¶

Each function you write should be focused on doing one thing. If a function is doing multiple things, it becomes more difficult to generalize and reuse.

Reference¶

A good book on modular programming in Python:

  • Modular Programming with Python, by Erik Westra

Pop quiz¶

2. Making your code modular makes it easier to do which of the following things? There may be more than one correct answer

  • Reuse your code
  • Write less code
  • Read your code
  • Collaborate on your code
In [ ]:
 

Pop quiz¶

2. Making your code modular makes it easier to do which of the following things? There may be more than one correct answer

  • Reuse your code
  • Write less code
  • Read your code
  • Collaborate on your code

Exercice¶

1. Imagine you are writing a program that executes a number of tasks and categorizes each task based on its execution time. Below is a small snippet of this program. Which of the following naming changes could make this code cleaner? There may be more than one correct answer.

t = end_time - start  # compute execution time
c = category(t)  # get category of task
print('Task Duration: {} seconds, Category: {}'.format(t, c)
  • None
  • Rename the variable start to start_time to make it consistent with end_time.
  • Rename the variable t to execution_time to make it more descriptive.
  • Rename the functioncategory to category_task to match the part of speech.
  • Rename the variable c to category to make it more descriptive.

Exercice -- Answer¶

1. Imagine you are writing a program that executes a number of tasks and categorizes each task based on its execution time. Below is a small snippet of this program. Which of the following naming changes could make this code cleaner? There may be more than one correct answer.

t = end_time - start  # compute execution time
c = category(t)  # get category of task
print('Task Duration: {} seconds, Category: {}'.format(t, c)

becomes

execution_time = end_time - start_time
category = categorize_task(execution_time)
print('Task Duration: {} seconds, Category: {}'.format(execution_time, category)

Exercice¶

2. Imagine you analyzed several stocks and calculated the ideal price, or limit price, at which you'd want to buy each stock. You write a program to iterate through your stocks and buy it if the current price is below or equal to the limit price you computed. Otherwise, you put it on a watchlist. Below are three ways of writing this code. Which of the following is the most clean?.

# Choice A
stock_limit_prices = {'LUX': 62.48, 'AAPL': 127.67, 'NVDA': 161.24}
for stock_ticker, stock_limit_price in stock_limit_prices.items():
    if stock_limit_price <= get_current_stock_price(stock_ticker):
        buy_stock(stock_ticker)
    else:
        watchlist_stock(stock_ticker)

# Choice B
prices = {'LUX': 62.48, 'AAPL': 127.67, 'NVDA': 161.24}
for ticker, price in prices.items():
    if price <= current_price(ticker):
        buy(ticker)
    else:
        watchlist(ticker)

# Choice C
limit_prices = {'LUX': 62.48, 'AAPL': 127.67, 'NVDA': 161.24}
for ticker, limit in limit_prices.items():
    if limit <= get_current_price(ticker):
        buy(ticker)
    else:
        watchlist(ticker)
  • Choice A
  • Choice B
  • Choice C

Exercice¶

2. Imagine you analyzed several stocks and calculated the ideal price, or limit price, at which you'd want to buy each stock. You write a program to iterate through your stocks and buy it if the current price is below or equal to the limit price you computed. Otherwise, you put it on a watchlist. Below are three ways of writing this code. Which of the following is the most clean?.

# Choice C
limit_prices = {'LUX': 62.48, 'AAPL': 127.67, 'NVDA': 161.24}
for ticker, limit in limit_prices.items():
    if limit <= get_current_price(ticker):
        buy(ticker)
    else:
        watchlist(ticker)
  • Choice A
  • Choice B
  • Choice C

Refactor code¶

Refactoring -- Restructuring your code to improve its internal structure without changing its external functionality. This gives you a chance to clean and modularize your program after you've got it working.

Writing documentation¶

Documentation -- Additional text or illustrated information that comes with or is embedded in the code of software. Documentation is helpful for clarifying complex parts of code, making your code easier to navigate, and quickly conveying how and why different components of your program are used. Several types of documentation can be added at different levels of your program:

  • Inline comments - line level
my_var = 42 # this is the ultimate answer
  • Docstrings - module and function level
def get_ultimate_aswer(question):
    '''This is the awesome function of the universe
    
    Parameters
    ----------
    question: str
    
    Return
    ------
    _: int
    
    '''
    return 42
  • Project documentation - project level

automating PEP8 & Linting¶

We have two ways to automate clean code:

  • pylint -- it is a Python static code analysis tool which looks for programming errors, helps enforcing a coding standard, sniffs for code smells and offers simple refactoring suggestions.
  • autopep8 -- automatically formats Python code to conform to the PEP 8 style guide.

pylint script_name.py will provide feedback on updates to make to your code, as well as a score out of 10 that can help you understand which improvements are most important.

autopep8 --in-place --aggressive --aggressive script_name.py will attempt to automatically clean up your code.

> pip install autopep8
> pip install pylint
> pylint first_day.py 
> autopep8 --in-place --aggressive --aggressive first_day.py
> pylint first_day.py

Decoding Python error¶

Learn to understand what Python is telling you

In [3]:
import pandas
df = pd.read_csv('../data/tweets-sentiment.csv')
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
Cell In [3], line 2
      1 import pandas
----> 2 df = pd.read_csv('../data/tweets-sentiment.csv')

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/pandas/util/_decorators.py:211, in deprecate_kwarg.<locals>._deprecate_kwarg.<locals>.wrapper(*args, **kwargs)
    209     else:
    210         kwargs[new_arg_name] = new_arg_value
--> 211 return func(*args, **kwargs)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/pandas/util/_decorators.py:317, in deprecate_nonkeyword_arguments.<locals>.decorate.<locals>.wrapper(*args, **kwargs)
    311 if len(args) > num_allow_args:
    312     warnings.warn(
    313         msg.format(arguments=arguments),
    314         FutureWarning,
    315         stacklevel=find_stack_level(inspect.currentframe()),
    316     )
--> 317 return func(*args, **kwargs)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/pandas/io/parsers/readers.py:950, in read_csv(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, squeeze, prefix, mangle_dupe_cols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, error_bad_lines, warn_bad_lines, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options)
    935 kwds_defaults = _refine_defaults_read(
    936     dialect,
    937     delimiter,
   (...)
    946     defaults={"delimiter": ","},
    947 )
    948 kwds.update(kwds_defaults)
--> 950 return _read(filepath_or_buffer, kwds)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/pandas/io/parsers/readers.py:605, in _read(filepath_or_buffer, kwds)
    602 _validate_names(kwds.get("names", None))
    604 # Create the parser.
--> 605 parser = TextFileReader(filepath_or_buffer, **kwds)
    607 if chunksize or iterator:
    608     return parser

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/pandas/io/parsers/readers.py:1442, in TextFileReader.__init__(self, f, engine, **kwds)
   1439     self.options["has_index_names"] = kwds["has_index_names"]
   1441 self.handles: IOHandles | None = None
-> 1442 self._engine = self._make_engine(f, self.engine)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/pandas/io/parsers/readers.py:1729, in TextFileReader._make_engine(self, f, engine)
   1727     is_text = False
   1728     mode = "rb"
-> 1729 self.handles = get_handle(
   1730     f,
   1731     mode,
   1732     encoding=self.options.get("encoding", None),
   1733     compression=self.options.get("compression", None),
   1734     memory_map=self.options.get("memory_map", False),
   1735     is_text=is_text,
   1736     errors=self.options.get("encoding_errors", "strict"),
   1737     storage_options=self.options.get("storage_options", None),
   1738 )
   1739 assert self.handles is not None
   1740 f = self.handles.handle

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/pandas/io/common.py:857, in get_handle(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options)
    852 elif isinstance(handle, str):
    853     # Check whether the filename is to be opened in binary mode.
    854     # Binary mode does not support 'encoding' and 'newline'.
    855     if ioargs.encoding and "b" not in ioargs.mode:
    856         # Encoding
--> 857         handle = open(
    858             handle,
    859             ioargs.mode,
    860             encoding=ioargs.encoding,
    861             errors=errors,
    862             newline="",
    863         )
    864     else:
    865         # Binary mode
    866         handle = open(handle, ioargs.mode)

FileNotFoundError: [Errno 2] No such file or directory: '../data/tweets-sentiment.csv'
In [ ]:
 
In [4]:
import pandas as pd
df = pd.read_csv('../data/tweet-sentiment.csv')
df.head()
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
Cell In [4], line 2
      1 import pandas as pd
----> 2 df = pd.read_csv('../data/tweet-sentiment.csv')
      3 df.head()

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/pandas/util/_decorators.py:211, in deprecate_kwarg.<locals>._deprecate_kwarg.<locals>.wrapper(*args, **kwargs)
    209     else:
    210         kwargs[new_arg_name] = new_arg_value
--> 211 return func(*args, **kwargs)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/pandas/util/_decorators.py:317, in deprecate_nonkeyword_arguments.<locals>.decorate.<locals>.wrapper(*args, **kwargs)
    311 if len(args) > num_allow_args:
    312     warnings.warn(
    313         msg.format(arguments=arguments),
    314         FutureWarning,
    315         stacklevel=find_stack_level(inspect.currentframe()),
    316     )
--> 317 return func(*args, **kwargs)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/pandas/io/parsers/readers.py:950, in read_csv(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, squeeze, prefix, mangle_dupe_cols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, error_bad_lines, warn_bad_lines, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options)
    935 kwds_defaults = _refine_defaults_read(
    936     dialect,
    937     delimiter,
   (...)
    946     defaults={"delimiter": ","},
    947 )
    948 kwds.update(kwds_defaults)
--> 950 return _read(filepath_or_buffer, kwds)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/pandas/io/parsers/readers.py:605, in _read(filepath_or_buffer, kwds)
    602 _validate_names(kwds.get("names", None))
    604 # Create the parser.
--> 605 parser = TextFileReader(filepath_or_buffer, **kwds)
    607 if chunksize or iterator:
    608     return parser

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/pandas/io/parsers/readers.py:1442, in TextFileReader.__init__(self, f, engine, **kwds)
   1439     self.options["has_index_names"] = kwds["has_index_names"]
   1441 self.handles: IOHandles | None = None
-> 1442 self._engine = self._make_engine(f, self.engine)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/pandas/io/parsers/readers.py:1729, in TextFileReader._make_engine(self, f, engine)
   1727     is_text = False
   1728     mode = "rb"
-> 1729 self.handles = get_handle(
   1730     f,
   1731     mode,
   1732     encoding=self.options.get("encoding", None),
   1733     compression=self.options.get("compression", None),
   1734     memory_map=self.options.get("memory_map", False),
   1735     is_text=is_text,
   1736     errors=self.options.get("encoding_errors", "strict"),
   1737     storage_options=self.options.get("storage_options", None),
   1738 )
   1739 assert self.handles is not None
   1740 f = self.handles.handle

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/pandas/io/common.py:857, in get_handle(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options)
    852 elif isinstance(handle, str):
    853     # Check whether the filename is to be opened in binary mode.
    854     # Binary mode does not support 'encoding' and 'newline'.
    855     if ioargs.encoding and "b" not in ioargs.mode:
    856         # Encoding
--> 857         handle = open(
    858             handle,
    859             ioargs.mode,
    860             encoding=ioargs.encoding,
    861             errors=errors,
    862             newline="",
    863         )
    864     else:
    865         # Binary mode
    866         handle = open(handle, ioargs.mode)

FileNotFoundError: [Errno 2] No such file or directory: '../data/tweet-sentiment.csv'
In [5]:
!%pwd
/Volumes/trappist1/missions/tbs/2022-2023/PYTHON-102/notebooks
In [6]:
import pandas as pd
fname = "/Volumes/trappist1/missions/tbs/2022-2023/PYTHON-102/campus/ue33-parttime/data/tweet-sentiment-withDay.csv"
df = pd.read_csv(fname)
df.head()
Out[6]:
target id date flag user text date_utc day_utc
0 0 1467810369 Mon Apr 06 22:19:45 PDT 2009 NO_QUERY _TheSpecialOne_ @switchfoot http://twitpic.com/2y1zl - Awww, t... 2009-04-07 06:12:45+00:00 2009-04-07
1 0 1467810672 Mon Apr 06 22:19:49 PDT 2009 NO_QUERY scotthamilton is upset that he can't update his Facebook by ... 2009-04-07 06:12:49+00:00 2009-04-07
2 0 1467810917 Mon Apr 06 22:19:53 PDT 2009 NO_QUERY mattycus @Kenichan I dived many times for the ball. Man... 2009-04-07 06:12:53+00:00 2009-04-07
3 0 1467811184 Mon Apr 06 22:19:57 PDT 2009 NO_QUERY ElleCTF my whole body feels itchy and like its on fire 2009-04-07 06:12:57+00:00 2009-04-07
4 0 1467811193 Mon Apr 06 22:19:57 PDT 2009 NO_QUERY Karoli @nationwideclass no, it's not behaving at all.... 2009-04-07 06:12:57+00:00 2009-04-07
In [7]:
def function_with_error():
    my_variable = 42
        my_second_variable = 24
    print(my_second_variable)
    
function_with_error()
  Cell In [7], line 3
    my_second_variable = 24
    ^
IndentationError: unexpected indent
In [8]:
def function_with_error():
    my_variable = 42
    my_second_variable = 24
    print(my_second_variable)
    
function_with_error()
24

SQLAlchemy¶

provides a nice “Pythonic” way of interacting with databases and integrate well with pandas

To install the module, run:

$ pip install SQLAlchemy
In [1]:
# Using SQLAlchemy with Pandas

import sqlalchemy as sa
import pandas as pd

# Creating the engine | defining which type of the database we use
engine = sa.create_engine("sqlite:////Volumes/trappist1/missions/tbs/2022-2023/PYTHON-102/campus/ue33-parttime/data/tweet-sentiment-withDay.db", echo=False)

# windows
#engine = sa.create_engine("sqlite:///C:/Users/username/<path-to-file/tweet-sentiment.db", echo=False)

# macOS/linux
#engine = sa.create_engine("sqlite:///Users/username/<path-to-file/tweet-sentiment.db", echo=False)

# another example of connection
# engine = sa.create_engine("postgresql://username:password@ip-address:port/database-name")

sa_connection = engine.connect()
In [2]:
sa_connection
Out[2]:
<sqlalchemy.engine.base.Connection at 0x7fc6b7386970>
In [12]:
# Getting list of tables availables in database
print(engine.table_names())
['tweets']
/var/folders/fc/ck893lx10jlfdzdx9785rsf00000gn/T/ipykernel_13847/4030562895.py:2: SADeprecationWarning: The Engine.table_names() method is deprecated and will be removed in a future release.  Please refer to Inspector.get_table_names(). (deprecated since: 1.4)
  print(engine.table_names())
In [3]:
# Extracting the data into a Pandas DataFrame
sql_query = "SELECT * FROM tweets"

tweets = pd.read_sql(sql_query, sa_connection)
tweets.head()
Out[3]:
target id date flag user text date_utc day_utc
0 0 1467810369 Mon Apr 06 22:19:45 PDT 2009 NO_QUERY _TheSpecialOne_ @switchfoot http://twitpic.com/2y1zl - Awww, t... 2009-04-07 06:12:45+00:00 2009-04-07
1 0 1467810672 Mon Apr 06 22:19:49 PDT 2009 NO_QUERY scotthamilton is upset that he can't update his Facebook by ... 2009-04-07 06:12:49+00:00 2009-04-07
2 0 1467810917 Mon Apr 06 22:19:53 PDT 2009 NO_QUERY mattycus @Kenichan I dived many times for the ball. Man... 2009-04-07 06:12:53+00:00 2009-04-07
3 0 1467811184 Mon Apr 06 22:19:57 PDT 2009 NO_QUERY ElleCTF my whole body feels itchy and like its on fire 2009-04-07 06:12:57+00:00 2009-04-07
4 0 1467811193 Mon Apr 06 22:19:57 PDT 2009 NO_QUERY Karoli @nationwideclass no, it's not behaving at all.... 2009-04-07 06:12:57+00:00 2009-04-07

Preliminary data analysis¶

In [14]:
# Number of rows
sql_query = """
    SELECT COUNT(*)
    FROM tweets
    """
pd.read_sql(sql_query, sa_connection)
Out[14]:
COUNT(*)
0 1600000

The dataset contains 1600000 tweets extracted using the Twitter API.

In [16]:
# Distribution of tweets
sql_query = """
    SELECT target, COUNT(*) as nb_per_sentiment
    FROM tweets
    GROUP BY target
"""
pd.read_sql(sql_query, sa_connection)
    SELECT target, COUNT(*) as nb_per_sentiment
    FROM tweets
    GROUP BY target

Out[16]:
target nb_per_sentiment
0 0 800000
1 4 800000

Each tweet has been annotated:

  • 0: Negative
  • 4: Positive

The dataset is evently distributed between these two annotations.

In [14]:
# Distribution of tweets per user
sql_query = """
    SELECT user, COUNT(target) as nb_tweets
    FROM tweets
    GROUP BY user
    LIMIT 10
    """
pd.read_sql(sql_query, sa_connection)
Out[14]:
user nb_tweets
0 000catnap000 6
1 000matthewkelly 1
2 000yea000 1
3 0010x0010 1
4 001BabyGirl 2
5 001trish 1
6 006jazzy 1
7 007LouiseOB 1
8 007_Chris_007 6
9 007buddha 1
In [18]:
# Distribution of tweets per user -- Ordered
sql_query = """
    SELECT user, COUNT(target) as nb_tweets
    FROM tweets
    GROUP BY user
    ORDER BY nb_tweets DESC --ASC
    LIMIT 10
    """
pd.read_sql(sql_query, sa_connection)
Out[18]:
user nb_tweets
0 lost_dog 549
1 webwoke 345
2 tweetpet 310
3 SallytheShizzle 281
4 VioletsCRUK 279
5 mcraddictal 276
6 tsarnick 248
7 what_bugs_u 246
8 Karen230683 238
9 DarkPiano 236

Exercice¶

  1. Load data from sqlite3 database instead of csv file
  2. Show the distribution of tweets per sentiment
In [4]:
import sqlalchemy as sa
import pandas as pd

# Creating the engine | defining which type of the database we use
engine = sa.create_engine("sqlite:////Users/samiadrappeau/Documents/TBS/PYTHON-102/tweet-sentiment-withDay.db", echo=False)
sa_connection = engine.connect()

sql_query = """
    SELECT *
    FROM tweets
    """

tweets = pd.read_sql(sql_query, sa_connection)
tweets.head()
---------------------------------------------------------------------------
OperationalError                          Traceback (most recent call last)
File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/engine/base.py:3361, in Engine._wrap_pool_connect(self, fn, connection)
   3360 try:
-> 3361     return fn()
   3362 except dialect.dbapi.Error as e:

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/base.py:320, in Pool.connect(self)
    313 """Return a DBAPI connection from the pool.
    314 
    315 The connection is instrumented such that when its
   (...)
    318 
    319 """
--> 320 return _ConnectionFairy._checkout(self)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/base.py:884, in _ConnectionFairy._checkout(cls, pool, threadconns, fairy)
    883 if not fairy:
--> 884     fairy = _ConnectionRecord.checkout(pool)
    886     fairy._pool = pool

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/base.py:486, in _ConnectionRecord.checkout(cls, pool)
    484 @classmethod
    485 def checkout(cls, pool):
--> 486     rec = pool._do_get()
    487     try:

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/impl.py:256, in NullPool._do_get(self)
    255 def _do_get(self):
--> 256     return self._create_connection()

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/base.py:266, in Pool._create_connection(self)
    264 """Called by subclasses to create a new ConnectionRecord."""
--> 266 return _ConnectionRecord(self)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/base.py:381, in _ConnectionRecord.__init__(self, pool, connect)
    380 if connect:
--> 381     self.__connect()
    382 self.finalize_callback = deque()

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/base.py:678, in _ConnectionRecord.__connect(self)
    677     with util.safe_reraise():
--> 678         pool.logger.debug("Error on connect(): %s", e)
    679 else:
    680     # in SQLAlchemy 1.4 the first_connect event is not used by
    681     # the engine, so this will usually not be set

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/util/langhelpers.py:70, in safe_reraise.__exit__(self, type_, value, traceback)
     69     if not self.warn_only:
---> 70         compat.raise_(
     71             exc_value,
     72             with_traceback=exc_tb,
     73         )
     74 else:

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/util/compat.py:208, in raise_(***failed resolving arguments***)
    207 try:
--> 208     raise exception
    209 finally:
    210     # credit to
    211     # https://cosmicpercolator.com/2016/01/13/exception-leaks-in-python-2-and-3/
    212     # as the __traceback__ object creates a cycle

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/base.py:673, in _ConnectionRecord.__connect(self)
    672 self.starttime = time.time()
--> 673 self.dbapi_connection = connection = pool._invoke_creator(self)
    674 pool.logger.debug("Created new connection %r", connection)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/engine/create.py:578, in create_engine.<locals>.connect(connection_record)
    577             return connection
--> 578 return dialect.connect(*cargs, **cparams)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/engine/default.py:598, in DefaultDialect.connect(self, *cargs, **cparams)
    596 def connect(self, *cargs, **cparams):
    597     # inherits the docstring from interfaces.Dialect.connect
--> 598     return self.dbapi.connect(*cargs, **cparams)

OperationalError: unable to open database file

The above exception was the direct cause of the following exception:

OperationalError                          Traceback (most recent call last)
Cell In [4], line 6
      4 # Creating the engine | defining which type of the database we use
      5 engine = sa.create_engine("sqlite:////Users/samiadrappeau/Documents/TBS/PYTHON-102/tweet-sentiment-withDay.db", echo=False)
----> 6 sa_connection = engine.connect()
      8 sql_query = """
      9     SELECT *
     10     FROM tweets
     11     """
     13 tweets = pd.read_sql(sql_query, sa_connection)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/engine/base.py:3315, in Engine.connect(self, close_with_result)
   3300 def connect(self, close_with_result=False):
   3301     """Return a new :class:`_engine.Connection` object.
   3302 
   3303     The :class:`_engine.Connection` object is a facade that uses a DBAPI
   (...)
   3312 
   3313     """
-> 3315     return self._connection_cls(self, close_with_result=close_with_result)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/engine/base.py:96, in Connection.__init__(self, engine, connection, close_with_result, _branch_from, _execution_options, _dispatch, _has_events, _allow_revalidate)
     91     self._has_events = _branch_from._has_events
     92 else:
     93     self._dbapi_connection = (
     94         connection
     95         if connection is not None
---> 96         else engine.raw_connection()
     97     )
     99     self._transaction = self._nested_transaction = None
    100     self.__savepoint_seq = 0

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/engine/base.py:3394, in Engine.raw_connection(self, _connection)
   3372 def raw_connection(self, _connection=None):
   3373     """Return a "raw" DBAPI connection from the connection pool.
   3374 
   3375     The returned object is a proxied version of the DBAPI
   (...)
   3392 
   3393     """
-> 3394     return self._wrap_pool_connect(self.pool.connect, _connection)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/engine/base.py:3364, in Engine._wrap_pool_connect(self, fn, connection)
   3362 except dialect.dbapi.Error as e:
   3363     if connection is None:
-> 3364         Connection._handle_dbapi_exception_noconnection(
   3365             e, dialect, self
   3366         )
   3367     else:
   3368         util.raise_(
   3369             sys.exc_info()[1], with_traceback=sys.exc_info()[2]
   3370         )

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/engine/base.py:2198, in Connection._handle_dbapi_exception_noconnection(cls, e, dialect, engine)
   2196     util.raise_(newraise, with_traceback=exc_info[2], from_=e)
   2197 elif should_wrap:
-> 2198     util.raise_(
   2199         sqlalchemy_exception, with_traceback=exc_info[2], from_=e
   2200     )
   2201 else:
   2202     util.raise_(exc_info[1], with_traceback=exc_info[2])

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/util/compat.py:208, in raise_(***failed resolving arguments***)
    205     exception.__cause__ = replace_context
    207 try:
--> 208     raise exception
    209 finally:
    210     # credit to
    211     # https://cosmicpercolator.com/2016/01/13/exception-leaks-in-python-2-and-3/
    212     # as the __traceback__ object creates a cycle
    213     del exception, replace_context, from_, with_traceback

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/engine/base.py:3361, in Engine._wrap_pool_connect(self, fn, connection)
   3359 dialect = self.dialect
   3360 try:
-> 3361     return fn()
   3362 except dialect.dbapi.Error as e:
   3363     if connection is None:

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/base.py:320, in Pool.connect(self)
    312 def connect(self):
    313     """Return a DBAPI connection from the pool.
    314 
    315     The connection is instrumented such that when its
   (...)
    318 
    319     """
--> 320     return _ConnectionFairy._checkout(self)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/base.py:884, in _ConnectionFairy._checkout(cls, pool, threadconns, fairy)
    881 @classmethod
    882 def _checkout(cls, pool, threadconns=None, fairy=None):
    883     if not fairy:
--> 884         fairy = _ConnectionRecord.checkout(pool)
    886         fairy._pool = pool
    887         fairy._counter = 0

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/base.py:486, in _ConnectionRecord.checkout(cls, pool)
    484 @classmethod
    485 def checkout(cls, pool):
--> 486     rec = pool._do_get()
    487     try:
    488         dbapi_connection = rec.get_connection()

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/impl.py:256, in NullPool._do_get(self)
    255 def _do_get(self):
--> 256     return self._create_connection()

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/base.py:266, in Pool._create_connection(self)
    263 def _create_connection(self):
    264     """Called by subclasses to create a new ConnectionRecord."""
--> 266     return _ConnectionRecord(self)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/base.py:381, in _ConnectionRecord.__init__(self, pool, connect)
    379 self.__pool = pool
    380 if connect:
--> 381     self.__connect()
    382 self.finalize_callback = deque()

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/base.py:678, in _ConnectionRecord.__connect(self)
    676 except Exception as e:
    677     with util.safe_reraise():
--> 678         pool.logger.debug("Error on connect(): %s", e)
    679 else:
    680     # in SQLAlchemy 1.4 the first_connect event is not used by
    681     # the engine, so this will usually not be set
    682     if pool.dispatch.first_connect:

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/util/langhelpers.py:70, in safe_reraise.__exit__(self, type_, value, traceback)
     68     self._exc_info = None  # remove potential circular references
     69     if not self.warn_only:
---> 70         compat.raise_(
     71             exc_value,
     72             with_traceback=exc_tb,
     73         )
     74 else:
     75     if not compat.py3k and self._exc_info and self._exc_info[1]:
     76         # emulate Py3K's behavior of telling us when an exception
     77         # occurs in an exception handler.

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/util/compat.py:208, in raise_(***failed resolving arguments***)
    205     exception.__cause__ = replace_context
    207 try:
--> 208     raise exception
    209 finally:
    210     # credit to
    211     # https://cosmicpercolator.com/2016/01/13/exception-leaks-in-python-2-and-3/
    212     # as the __traceback__ object creates a cycle
    213     del exception, replace_context, from_, with_traceback

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/pool/base.py:673, in _ConnectionRecord.__connect(self)
    671 try:
    672     self.starttime = time.time()
--> 673     self.dbapi_connection = connection = pool._invoke_creator(self)
    674     pool.logger.debug("Created new connection %r", connection)
    675     self.fresh = True

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/engine/create.py:578, in create_engine.<locals>.connect(connection_record)
    576         if connection is not None:
    577             return connection
--> 578 return dialect.connect(*cargs, **cparams)

File ~/anaconda3/envs/datascience/lib/python3.8/site-packages/sqlalchemy/engine/default.py:598, in DefaultDialect.connect(self, *cargs, **cparams)
    596 def connect(self, *cargs, **cparams):
    597     # inherits the docstring from interfaces.Dialect.connect
--> 598     return self.dbapi.connect(*cargs, **cparams)

OperationalError: (sqlite3.OperationalError) unable to open database file
(Background on this error at: https://sqlalche.me/e/14/e3q8)

Beautifying Streamlit app¶

Sidebar¶

Hand-on: Find in Streamlit documentation how to create a sidebar in Streamlit

Columns¶

Hand-on: Find in Streamlit documentation how to create columns in Streamlit

Exercice¶

  1. Place all data and distribution of tweets per sentiment in two separate screens
  2. Make side-by-side word-cloud per sentiment type

Part #3¶

Objectives of the day:

  • DATA APP
    • Write a REST API
      • presentation of Flask
    • Interact with a REST API
      • presentation of requests

Flask¶

Flask is a web framework, it's a Python module that lets you develop web applications easily.

  • documentation: https://flask.palletsprojects.com/en/2.0.x/#api-reference

Hello World Flask server¶

Install FLASK

$ pip install flask
# ou
$ conda install -c anaconda flask

Open a new file flask-hello_world.py and copy the following code:

from flask import Flask

app = Flask(__name__)


@app.route('/')
def hello():
    return 'Hello, World!'

Then save it.

In the preceding code block, you first import the Flask object from the flask package. You then use it to create your Flask application instance with the name app. You pass the special variable __name__ that holds the name of the current Python module. It’s used to tell the instance where it’s located—you need this because Flask sets up some paths behind the scenes.

Once you create the app instance, you use it to handle incoming web requests and send responses to the user. @app.route is a decorator that turns a regular Python function into a Flask view function, which converts the function’s return value into an HTTP response to be displayed by an HTTP client, such as a web browser. You pass the value '/' to @app.route() to signify that this function will respond to web requests for the URL /, which is the main URL.

The hello() view function returns the string 'Hello, World!' as a response.

Run the Hello World Flask server¶

To run your web application, you’ll first tell Flask where to find the application (the hello-flask.py file in your case) with the FLASK_APP environment variable.

Please execute the following command in your terminal, making sure you are located where the script is:

> export FLASK_APP=hello-flask
> export FLASK_ENV=development

#for windows machine
# > set FLASK_APP=hello-flask
# > set FLASK_ENV=development
> flask run

You should see something like this:

Output
 * Serving Flask app "hello" (lazy loading)
 * Environment: development
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 813-894-335

Bravo!¶

You are running your first REST API!

Install first the folllowing modules:

$ pip install textblob
# ou
$ conda install -c conda-forge textblob

Now, open a new file model_server.py and copy the following code into it:

from flask import Flask, jsonify, request
from textblob import TextBlob

app = Flask(__name__)

# Add all the routes you want below
@app.route("/predict", methods=['GET'])
def get_prediction():
    text = request.args.get('text')
    testimonial = TextBlob(text).sentiment.polarity
    return jsonify(polarity=testimonial)
 
if __name__ == '__main__':
    app.run()

Then save it.

Now, stop the previous running Flask server (with Ctrl-C), and execute the following commands:

> export FLASK_APP=model_server
> flask run

Your first Machine Learning server is up and running!

Now, open your favorite browser and enter the following URL:

http://127.0.0.1:5000/predict?text="this is awesome!"

Requests¶

  • documentation: https://docs.python-requests.org/en/latest/

Requests is an elegant and simple Python library built to handle HTTP requests in python easily.

But what is a HTTP request?
HTTP is a set of protocols designed to enable communication between clients and servers.

A client is typically a local computer or device similar to what you are using to view this page.

A HTTP request is the message sent (or received) from your local computer to a web server hosting, typically hosting a website.

For example, when you go to any internet website from your browser, the browser is sending a HTTP request and receives an appropriate ‘response’ from the host server.

Requests is an easy-to-use library with a lot of features ranging from passing additional parameters in URLs, sending custom headers, SSL Verification, processing the received response etc.

Most commenly-used HTTP methods to request:¶

  • GET (=read operation)
  • POST (=create operation)
  • PUT (=update operation)
  • PATCH (=update operation)
  • DELETE (=delete operation)

What is a GET and POST request?¶

A GET request is used to request data from a specific server. It is the most common type of request. This is synonymous to you visiting the homepage of a website from your browser.

Another common type of request is the POST request, which is used to send data to a host server for further processing, like, to update a resource, such as a database. What is this synonymous to in real world? For example, most data that you submit through forms in various websites is sent and processed as a POST request.

GET Method¶

In [1]:
import requests
response = requests.get('https://www.python.org/')
print(response)
<Response [200]>

STATUS Code¶

Status codes are issued by a server in response to a client’s request made to the server.

Use the r.status_code command to return the status code for your request.

In [2]:
print(response.status_code)
200
  • A response of 200 means Success.
  • A response of 300 means Redirected.
  • A response of 400 means Client Error.
  • A response of 404 means Page Not Found Error.
  • A response of 500 means Server Error.

In general, any status code less than 400 means, the request was processed successfully. If it is 400 and above, some sort of error occurred.

In [6]:
if r.status_code == 200:
    print("It's a great Success!!")
elif r.status_code == 404:
    print("Page not found")
It's a great Success!!

Contents of the Response object¶

dir(r) function is used to get details about what all useful information we can get from the data we retrived.

In [3]:
r_list = []
for c in dir(response):
    if not c.startswith("_"):
        r_list.append(c)
print(r_list)
['apparent_encoding', 'close', 'connection', 'content', 'cookies', 'elapsed', 'encoding', 'headers', 'history', 'is_permanent_redirect', 'is_redirect', 'iter_content', 'iter_lines', 'json', 'links', 'next', 'ok', 'raise_for_status', 'raw', 'reason', 'request', 'status_code', 'text', 'url']
In [5]:
[c for c in dir(response) if not c.startswith("_")]
Out[5]:
['apparent_encoding',
 'close',
 'connection',
 'content',
 'cookies',
 'elapsed',
 'encoding',
 'headers',
 'history',
 'is_permanent_redirect',
 'is_redirect',
 'iter_content',
 'iter_lines',
 'json',
 'links',
 'next',
 'ok',
 'raise_for_status',
 'raw',
 'reason',
 'request',
 'status_code',
 'text',
 'url']
In [6]:
print(response.url)
https://www.python.org/
In [7]:
# Raw Content
print(response.content[:800])
b'<!doctype html>\n<!--[if lt IE 7]>   <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9">   <![endif]-->\n<!--[if IE 7]>      <html class="no-js ie7 lt-ie8 lt-ie9">          <![endif]-->\n<!--[if IE 8]>      <html class="no-js ie8 lt-ie9">                 <![endif]-->\n<!--[if gt IE 8]><!--><html class="no-js" lang="en" dir="ltr">  <!--<![endif]-->\n\n<head>\n    <!-- Google tag (gtag.js) -->\n    <script async src="https://www.googletagmanager.com/gtag/js?id=G-TF35YF9CVH"></script>\n    <script>\n      window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag(\'js\', new Date());\n      gtag(\'config\', \'G-TF35YF9CVH\');\n    </script>\n\n    <meta charset="utf-8">\n    <meta http-equiv="X-UA-Compatible" content="IE=edge">\n\n    <link rel="prefetch" href="//ajax.googleap'
In [8]:
# Content as text
print(response.text[:800])
<!doctype html>
<!--[if lt IE 7]>   <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9">   <![endif]-->
<!--[if IE 7]>      <html class="no-js ie7 lt-ie8 lt-ie9">          <![endif]-->
<!--[if IE 8]>      <html class="no-js ie8 lt-ie9">                 <![endif]-->
<!--[if gt IE 8]><!--><html class="no-js" lang="en" dir="ltr">  <!--<![endif]-->

<head>
    <!-- Google tag (gtag.js) -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-TF35YF9CVH"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());
      gtag('config', 'G-TF35YF9CVH');
    </script>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <link rel="prefetch" href="//ajax.googleap
In [1]:
import requests
# This is the REST API we just developed earlier
sample_text = 'This is horrible!'
r = requests.get(f"http://127.0.0.1:5000/predict?text={sample_text}")
print(r.content)
print(r.text)
b'{"polarity":-1.0}\n'
{"polarity":-1.0}

In [2]:
print(r.json())
{'polarity': -1.0}
In [3]:
print(r.json()['polarity'])
-1.0
In [4]:
import requests
sample_text = 'This is awesome!'
r = requests.get(f"http://127.0.0.1:5000/predict?text={sample_text}")
print(r.json()['polarity'])
1.0
In [5]:
import requests
sample_text = 'This is ok-ish.'
r = requests.get(f"http://127.0.0.1:5000/predict?text={sample_text}")
print(r.json()['polarity'])
0.0
In [20]:
import requests
r = requests.get('https://api.github.com/events')
print(r.json())
[{'id': '20038546522', 'type': 'CreateEvent', 'actor': {'id': 90335716, 'login': 'dub6ix', 'display_login': 'dub6ix', 'gravatar_id': '', 'url': 'https://api.github.com/users/dub6ix', 'avatar_url': 'https://avatars.githubusercontent.com/u/90335716?'}, 'repo': {'id': 454172086, 'name': 'nuggxyz/dotnugg-grammar', 'url': 'https://api.github.com/repos/nuggxyz/dotnugg-grammar'}, 'payload': {'ref': '0.1.8', 'ref_type': 'tag', 'master_branch': 'main', 'description': None, 'pusher_type': 'user'}, 'public': True, 'created_at': '2022-02-02T14:23:30Z', 'org': {'id': 93823471, 'login': 'nuggxyz', 'gravatar_id': '', 'url': 'https://api.github.com/orgs/nuggxyz', 'avatar_url': 'https://avatars.githubusercontent.com/u/93823471?'}}, {'id': '20038546691', 'type': 'CreateEvent', 'actor': {'id': 10166338, 'login': 'akashtalole', 'display_login': 'akashtalole', 'gravatar_id': '', 'url': 'https://api.github.com/users/akashtalole', 'avatar_url': 'https://avatars.githubusercontent.com/u/10166338?'}, 'repo': {'id': 454800011, 'name': 'akashtalole/node-red-contrib-thingsboard-rest-api-auth', 'url': 'https://api.github.com/repos/akashtalole/node-red-contrib-thingsboard-rest-api-auth'}, 'payload': {'ref': 'main', 'ref_type': 'branch', 'master_branch': 'main', 'description': 'node-red-contrib-thingsboard-rest-api-auth', 'pusher_type': 'user'}, 'public': True, 'created_at': '2022-02-02T14:23:31Z'}, {'id': '20038546603', 'type': 'IssuesEvent', 'actor': {'id': 1526295, 'login': 'sldblog', 'display_login': 'sldblog', 'gravatar_id': '', 'url': 'https://api.github.com/users/sldblog', 'avatar_url': 'https://avatars.githubusercontent.com/u/1526295?'}, 'repo': {'id': 312544484, 'name': 'ministryofjustice/hmpps-interventions-ui', 'url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui'}, 'payload': {'action': 'closed', 'issue': {'url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/1197', 'repository_url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui', 'labels_url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/1197/labels{/name}', 'comments_url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/1197/comments', 'events_url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/1197/events', 'html_url': 'https://github.com/ministryofjustice/hmpps-interventions-ui/issues/1197', 'id': 1117364167, 'node_id': 'I_kwDOEqEM5M5CmZ_H', 'number': 1197, 'title': 'A branch protection setting is not enabled: Include administrators', 'user': {'login': 'AntonyBishop', 'id': 36888942, 'node_id': 'MDQ6VXNlcjM2ODg4OTQy', 'avatar_url': 'https://avatars.githubusercontent.com/u/36888942?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/AntonyBishop', 'html_url': 'https://github.com/AntonyBishop', 'followers_url': 'https://api.github.com/users/AntonyBishop/followers', 'following_url': 'https://api.github.com/users/AntonyBishop/following{/other_user}', 'gists_url': 'https://api.github.com/users/AntonyBishop/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/AntonyBishop/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/AntonyBishop/subscriptions', 'organizations_url': 'https://api.github.com/users/AntonyBishop/orgs', 'repos_url': 'https://api.github.com/users/AntonyBishop/repos', 'events_url': 'https://api.github.com/users/AntonyBishop/events{/privacy}', 'received_events_url': 'https://api.github.com/users/AntonyBishop/received_events', 'type': 'User', 'site_admin': False}, 'labels': [], 'state': 'closed', 'locked': False, 'assignee': None, 'assignees': [], 'milestone': None, 'comments': 1, 'created_at': '2022-01-28T12:45:33Z', 'updated_at': '2022-02-02T14:23:29Z', 'closed_at': '2022-02-02T14:23:29Z', 'author_association': 'NONE', 'active_lock_reason': None, 'body': 'Hi there\nThe default branch protection setting called Include administrators is not enabled for this repository\nSee repository settings/Branches/Branch protection rules\nEither add a new Branch protection rule or edit the existing branch protection rule and select the Include administrators option\nThis will enable the branch protection rules to admin uses as well\nSee the repository standards: https://github.com/ministryofjustice/github-repository-standards\nSee the report: https://operations-engineering-reports.cloud-platform.service.justice.gov.uk/github_repositories\nPlease contact Operations Engineering on Slack #ask-operations-engineering, if you need any assistance\n', 'reactions': {'url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/1197/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/1197/timeline', 'performed_via_github_app': None}}, 'public': True, 'created_at': '2022-02-02T14:23:31Z', 'org': {'id': 2203574, 'login': 'ministryofjustice', 'gravatar_id': '', 'url': 'https://api.github.com/orgs/ministryofjustice', 'avatar_url': 'https://avatars.githubusercontent.com/u/2203574?'}}, {'id': '20038546684', 'type': 'PushEvent', 'actor': {'id': 36798399, 'login': 'Ishoshot', 'display_login': 'Ishoshot', 'gravatar_id': '', 'url': 'https://api.github.com/users/Ishoshot', 'avatar_url': 'https://avatars.githubusercontent.com/u/36798399?'}, 'repo': {'id': 452715731, 'name': 'Ishoshot/morebitcoin', 'url': 'https://api.github.com/repos/Ishoshot/morebitcoin'}, 'payload': {'push_id': 8993439111, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/master', 'head': '0a0e70acab5f3111496ec17b9b67e6224f3c3930', 'before': '767048afe423fc336f8f667c16f3126b9bd083de', 'commits': [{'sha': '0a0e70acab5f3111496ec17b9b67e6224f3c3930', 'author': {'email': 'ishoshot@gmail.com', 'name': 'ishoshot'}, 'message': 'Dashboard ChartData bug', 'distinct': True, 'url': 'https://api.github.com/repos/Ishoshot/morebitcoin/commits/0a0e70acab5f3111496ec17b9b67e6224f3c3930'}]}, 'public': True, 'created_at': '2022-02-02T14:23:31Z'}, {'id': '20038546503', 'type': 'PushEvent', 'actor': {'id': 14362322, 'login': 'luchoaglp', 'display_login': 'luchoaglp', 'gravatar_id': '', 'url': 'https://api.github.com/users/luchoaglp', 'avatar_url': 'https://avatars.githubusercontent.com/u/14362322?'}, 'repo': {'id': 453433596, 'name': 'luchoaglp/creditoazteca', 'url': 'https://api.github.com/repos/luchoaglp/creditoazteca'}, 'payload': {'push_id': 8993439005, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/main', 'head': '10dcb266af7bb2039d01f6f54e649ccde4a9cddf', 'before': 'c23de70260cf64e36ad5d0bb173f87852b23eaa6', 'commits': [{'sha': '10dcb266af7bb2039d01f6f54e649ccde4a9cddf', 'author': {'email': 'lucho_aglp@hotmail.com', 'name': 'luchoaglp'}, 'message': 'Update', 'distinct': True, 'url': 'https://api.github.com/repos/luchoaglp/creditoazteca/commits/10dcb266af7bb2039d01f6f54e649ccde4a9cddf'}]}, 'public': True, 'created_at': '2022-02-02T14:23:30Z'}, {'id': '20038546704', 'type': 'PushEvent', 'actor': {'id': 42819689, 'login': 'whitesource-bolt-for-github[bot]', 'display_login': 'whitesource-bolt-for-github', 'gravatar_id': '', 'url': 'https://api.github.com/users/whitesource-bolt-for-github[bot]', 'avatar_url': 'https://avatars.githubusercontent.com/u/42819689?'}, 'repo': {'id': 454805278, 'name': 'LaudateCorpus1/haul', 'url': 'https://api.github.com/repos/LaudateCorpus1/haul'}, 'payload': {'push_id': 8993439123, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/whitesource/configure', 'head': 'f1ec06f177d707ae8191f423a3da9bd8b9e8854e', 'before': 'bfc5578b541d935ebc58356ae20e15a726c5284d', 'commits': [{'sha': 'f1ec06f177d707ae8191f423a3da9bd8b9e8854e', 'author': {'email': '42819689+whitesource-bolt-for-github[bot]@users.noreply.github.com', 'name': 'whitesource-bolt-for-github[bot]'}, 'message': 'Add .whitesource configuration file', 'distinct': True, 'url': 'https://api.github.com/repos/LaudateCorpus1/haul/commits/f1ec06f177d707ae8191f423a3da9bd8b9e8854e'}]}, 'public': True, 'created_at': '2022-02-02T14:23:31Z'}, {'id': '20038546728', 'type': 'PushEvent', 'actor': {'id': 57829583, 'login': 'etkmlm', 'display_login': 'etkmlm', 'gravatar_id': '', 'url': 'https://api.github.com/users/etkmlm', 'avatar_url': 'https://avatars.githubusercontent.com/u/57829583?'}, 'repo': {'id': 427765240, 'name': 'etkmlm/CynthMusic', 'url': 'https://api.github.com/repos/etkmlm/CynthMusic'}, 'payload': {'push_id': 8993439206, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/master', 'head': '99b7992544765639d3c1e7402a663ef6cae4a9e9', 'before': 'c54014d51d75b33144701baeb12194d7a0694761', 'commits': [{'sha': '99b7992544765639d3c1e7402a663ef6cae4a9e9', 'author': {'email': 'furkanmahmutyilmaz@gmail.com', 'name': 'etkmlm'}, 'message': 'update', 'distinct': True, 'url': 'https://api.github.com/repos/etkmlm/CynthMusic/commits/99b7992544765639d3c1e7402a663ef6cae4a9e9'}]}, 'public': True, 'created_at': '2022-02-02T14:23:31Z'}, {'id': '20038546712', 'type': 'ForkEvent', 'actor': {'id': 71681815, 'login': 'LaudateCorpus1', 'display_login': 'LaudateCorpus1', 'gravatar_id': '', 'url': 'https://api.github.com/users/LaudateCorpus1', 'avatar_url': 'https://avatars.githubusercontent.com/u/71681815?'}, 'repo': {'id': 198903446, 'name': 'discord/react-async-component', 'url': 'https://api.github.com/repos/discord/react-async-component'}, 'payload': {'forkee': {'id': 454805316, 'node_id': 'R_kgDOGxvHRA', 'name': 'react-async-component', 'full_name': 'LaudateCorpus1/react-async-component', 'private': False, 'owner': {'login': 'LaudateCorpus1', 'id': 71681815, 'node_id': 'MDQ6VXNlcjcxNjgxODE1', 'avatar_url': 'https://avatars.githubusercontent.com/u/71681815?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/LaudateCorpus1', 'html_url': 'https://github.com/LaudateCorpus1', 'followers_url': 'https://api.github.com/users/LaudateCorpus1/followers', 'following_url': 'https://api.github.com/users/LaudateCorpus1/following{/other_user}', 'gists_url': 'https://api.github.com/users/LaudateCorpus1/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/LaudateCorpus1/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/LaudateCorpus1/subscriptions', 'organizations_url': 'https://api.github.com/users/LaudateCorpus1/orgs', 'repos_url': 'https://api.github.com/users/LaudateCorpus1/repos', 'events_url': 'https://api.github.com/users/LaudateCorpus1/events{/privacy}', 'received_events_url': 'https://api.github.com/users/LaudateCorpus1/received_events', 'type': 'User', 'site_admin': False}, 'html_url': 'https://github.com/LaudateCorpus1/react-async-component', 'description': 'Resolve components asynchronously, with support for code splitting and advanced server side rendering use cases.', 'fork': True, 'url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component', 'forks_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/forks', 'keys_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/teams', 'hooks_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/hooks', 'issue_events_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/issues/events{/number}', 'events_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/events', 'assignees_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/assignees{/user}', 'branches_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/branches{/branch}', 'tags_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/tags', 'blobs_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/languages', 'stargazers_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/stargazers', 'contributors_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/contributors', 'subscribers_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/subscribers', 'subscription_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/subscription', 'commits_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/contents/{+path}', 'compare_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/merges', 'archive_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/downloads', 'issues_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/issues{/number}', 'pulls_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/labels{/name}', 'releases_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/releases{/id}', 'deployments_url': 'https://api.github.com/repos/LaudateCorpus1/react-async-component/deployments', 'created_at': '2022-02-02T14:23:27Z', 'updated_at': '2021-04-28T21:28:49Z', 'pushed_at': '2019-07-25T21:34:03Z', 'git_url': 'git://github.com/LaudateCorpus1/react-async-component.git', 'ssh_url': 'git@github.com:LaudateCorpus1/react-async-component.git', 'clone_url': 'https://github.com/LaudateCorpus1/react-async-component.git', 'svn_url': 'https://github.com/LaudateCorpus1/react-async-component', 'homepage': '', 'size': 450, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'mit', 'name': 'MIT License', 'spdx_id': 'MIT', 'url': 'https://api.github.com/licenses/mit', 'node_id': 'MDc6TGljZW5zZTEz'}, 'allow_forking': True, 'is_template': False, 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'public': True}}, 'public': True, 'created_at': '2022-02-02T14:23:31Z', 'org': {'id': 1965106, 'login': 'discord', 'gravatar_id': '', 'url': 'https://api.github.com/orgs/discord', 'avatar_url': 'https://avatars.githubusercontent.com/u/1965106?'}}, {'id': '20038546667', 'type': 'PushEvent', 'actor': {'id': 11934090, 'login': 'NickleDave', 'display_login': 'NickleDave', 'gravatar_id': '', 'url': 'https://api.github.com/users/NickleDave', 'avatar_url': 'https://avatars.githubusercontent.com/u/11934090?'}, 'repo': {'id': 369936952, 'name': 'NickleDave/vocalpy', 'url': 'https://api.github.com/repos/NickleDave/vocalpy'}, 'payload': {'push_id': 8993439062, 'size': 7, 'distinct_size': 7, 'ref': 'refs/heads/dev-0.1.0', 'head': '207fdb21d2d355a7d60d806d790f74764a92f784', 'before': '2fa1b3e2506c94c966cc35324344cc5099995364', 'commits': [{'sha': 'db2a2fc71e4eff8f1d3d6ecbee8a4224006dada8', 'author': {'email': 'nickledave@users.noreply.github.com', 'name': 'David Nicholson'}, 'message': 'revise src/vocalpy/dataclasses/audio.py', 'distinct': True, 'url': 'https://api.github.com/repos/NickleDave/vocalpy/commits/db2a2fc71e4eff8f1d3d6ecbee8a4224006dada8'}, {'sha': 'd9384b38a10ae8a58d67a6276837bd07892db5be', 'author': {'email': 'nickledave@users.noreply.github.com', 'name': 'David Nicholson'}, 'message': 'add tests/test_audio.py', 'distinct': True, 'url': 'https://api.github.com/repos/NickleDave/vocalpy/commits/d9384b38a10ae8a58d67a6276837bd07892db5be'}, {'sha': '07a848d271b677c1e203b1bf674d5426a28d6a2a', 'author': {'email': 'nickledave@users.noreply.github.com', 'name': 'David Nicholson'}, 'message': 'add .pre-commit-config.yaml', 'distinct': True, 'url': 'https://api.github.com/repos/NickleDave/vocalpy/commits/07a848d271b677c1e203b1bf674d5426a28d6a2a'}, {'sha': '7d52655873b7e40db728bf60d4e5916f03d9164f', 'author': {'email': 'nickledave@users.noreply.github.com', 'name': 'David Nicholson'}, 'message': 'add noxfile.py', 'distinct': True, 'url': 'https://api.github.com/repos/NickleDave/vocalpy/commits/7d52655873b7e40db728bf60d4e5916f03d9164f'}, {'sha': 'aaaf7b0f7ce448575443b0587a47ea8af3db5548', 'author': {'email': 'nickledave@users.noreply.github.com', 'name': 'David Nicholson'}, 'message': 'rewrite spectrogram to lazy load', 'distinct': True, 'url': 'https://api.github.com/repos/NickleDave/vocalpy/commits/aaaf7b0f7ce448575443b0587a47ea8af3db5548'}, {'sha': 'c4d880e3fa2bac229080b935e0e042f19a6ad7d3', 'author': {'email': 'nickledave@users.noreply.github.com', 'name': 'David Nicholson'}, 'message': 'move test_audio into tests/test_dataclasses/', 'distinct': True, 'url': 'https://api.github.com/repos/NickleDave/vocalpy/commits/c4d880e3fa2bac229080b935e0e042f19a6ad7d3'}, {'sha': '207fdb21d2d355a7d60d806d790f74764a92f784', 'author': {'email': 'nickledave@users.noreply.github.com', 'name': 'David Nicholson'}, 'message': 'WIP: add tests/test_dataclasses/test_spectrogram.py', 'distinct': True, 'url': 'https://api.github.com/repos/NickleDave/vocalpy/commits/207fdb21d2d355a7d60d806d790f74764a92f784'}]}, 'public': True, 'created_at': '2022-02-02T14:23:31Z'}, {'id': '20038546666', 'type': 'PushEvent', 'actor': {'id': 43951, 'login': 'joschi', 'display_login': 'joschi', 'gravatar_id': '', 'url': 'https://api.github.com/users/joschi', 'avatar_url': 'https://avatars.githubusercontent.com/u/43951?'}, 'repo': {'id': 315058783, 'name': 'joschi/asdf-vm-twitter', 'url': 'https://api.github.com/repos/joschi/asdf-vm-twitter'}, 'payload': {'push_id': 8993439101, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/main', 'head': 'ee6e8893fd37096190d74539303ca25688c642db', 'before': 'accb3220620ca0199f21d016fc4bc87b23ba6819', 'commits': [{'sha': 'ee6e8893fd37096190d74539303ca25688c642db', 'author': {'email': 'joschi@users.noreply.github.com', 'name': 'joschi'}, 'message': '🤖 Add new tweets 🐦', 'distinct': True, 'url': 'https://api.github.com/repos/joschi/asdf-vm-twitter/commits/ee6e8893fd37096190d74539303ca25688c642db'}]}, 'public': True, 'created_at': '2022-02-02T14:23:31Z'}, {'id': '20038546663', 'type': 'PullRequestReviewEvent', 'actor': {'id': 37936606, 'login': 'github-learning-lab[bot]', 'display_login': 'github-learning-lab', 'gravatar_id': '', 'url': 'https://api.github.com/users/github-learning-lab[bot]', 'avatar_url': 'https://avatars.githubusercontent.com/u/37936606?'}, 'repo': {'id': 448401719, 'name': 'programmer-georgia/github-actions-for-ci', 'url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci'}, 'payload': {'action': 'created', 'review': {'id': 870611919, 'node_id': 'PRR_kwDOGroRN84z5HvP', 'user': {'login': 'github-learning-lab[bot]', 'id': 37936606, 'node_id': 'MDM6Qm90Mzc5MzY2MDY=', 'avatar_url': 'https://avatars.githubusercontent.com/in/10572?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D', 'html_url': 'https://github.com/apps/github-learning-lab', 'followers_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/followers', 'following_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/following{/other_user}', 'gists_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/subscriptions', 'organizations_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/orgs', 'repos_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/repos', 'events_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/events{/privacy}', 'received_events_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/received_events', 'type': 'Bot', 'site_admin': False}, 'body': None, 'commit_id': '3d8bdc3c3b1bd57f2295509b26c532c2dc26871d', 'submitted_at': '2022-02-02T14:23:29Z', 'state': 'commented', 'html_url': 'https://github.com/programmer-georgia/github-actions-for-ci/pull/6#pullrequestreview-870611919', 'pull_request_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/pulls/6', 'author_association': 'CONTRIBUTOR', '_links': {'html': {'href': 'https://github.com/programmer-georgia/github-actions-for-ci/pull/6#pullrequestreview-870611919'}, 'pull_request': {'href': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/pulls/6'}}}, 'pull_request': {'url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/pulls/6', 'id': 838342401, 'node_id': 'PR_kwDOGroRN84x-BcB', 'html_url': 'https://github.com/programmer-georgia/github-actions-for-ci/pull/6', 'diff_url': 'https://github.com/programmer-georgia/github-actions-for-ci/pull/6.diff', 'patch_url': 'https://github.com/programmer-georgia/github-actions-for-ci/pull/6.patch', 'issue_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/issues/6', 'number': 6, 'state': 'open', 'locked': False, 'title': 'A custom workflow', 'user': {'login': 'github-learning-lab[bot]', 'id': 37936606, 'node_id': 'MDM6Qm90Mzc5MzY2MDY=', 'avatar_url': 'https://avatars.githubusercontent.com/in/10572?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D', 'html_url': 'https://github.com/apps/github-learning-lab', 'followers_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/followers', 'following_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/following{/other_user}', 'gists_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/subscriptions', 'organizations_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/orgs', 'repos_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/repos', 'events_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/events{/privacy}', 'received_events_url': 'https://api.github.com/users/github-learning-lab%5Bbot%5D/received_events', 'type': 'Bot', 'site_admin': False}, 'body': "# Partial workflow\n\nRemember the [custom workflow](https://github.com/programmer-georgia/github-actions-for-ci/issues/4) we are attempting to create for the team? Here's our status on the list of requirements we defined:\n\n- :white_check_mark: **test against multiple targets** so that we know if our supported operating systems and Node.js versions are working\n- :white_check_mark: **dedicated test job** so that we can separate out build from test details\n- :white_check_mark: **access to build artifacts** so that we can deploy them to a target environment\n- **branch protections** so that the `main` branch can't be deleted or inadvertently broken\n- **required reviews** so that any pull requests are double checked by teammates\n- **obvious approvals** so we can merge quickly and potentially automate merges and deployments\n\nThe last three remaining items don't really belong in a `code, build, and test` pipeline because they have to do with processes that involve humans.\n\n## Step 14: Automate the review process\n\nGitHub Actions can run multiple workflows for different event triggers. Let's create a new approval workflow that'll work together with our Node.js workflow.\n\n### :keyboard: Activity: Add a new workflow file to automate the team's review process\n\n1. Create a [new file](https://github.com/programmer-georgia/github-actions-for-ci/new/team-workflow/?filename=.github/workflows/approval-workflow.yml), `.github/workflows/approval-workflow.yml`, on this branch\n1. Enter a name for your workflow in the new file, something like:\n    ```yaml\n    name: Team awesome's approval workflow\n    ```\n\nI'll respond when you commit to this branch.\n", 'created_at': '2022-02-02T14:07:12Z', 'updated_at': '2022-02-02T14:23:29Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': '89a43d463fd28691902ccb165e09e7385b63b0bd', 'assignee': None, 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/pulls/6/commits', 'review_comments_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/pulls/6/comments', 'review_comment_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/issues/6/comments', 'statuses_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/statuses/3d8bdc3c3b1bd57f2295509b26c532c2dc26871d', 'head': {'label': 'programmer-georgia:team-workflow', 'ref': 'team-workflow', 'sha': '3d8bdc3c3b1bd57f2295509b26c532c2dc26871d', 'user': {'login': 'programmer-georgia', 'id': 96337743, 'node_id': 'U_kgDOBb3_Tw', 'avatar_url': 'https://avatars.githubusercontent.com/u/96337743?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/programmer-georgia', 'html_url': 'https://github.com/programmer-georgia', 'followers_url': 'https://api.github.com/users/programmer-georgia/followers', 'following_url': 'https://api.github.com/users/programmer-georgia/following{/other_user}', 'gists_url': 'https://api.github.com/users/programmer-georgia/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/programmer-georgia/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/programmer-georgia/subscriptions', 'organizations_url': 'https://api.github.com/users/programmer-georgia/orgs', 'repos_url': 'https://api.github.com/users/programmer-georgia/repos', 'events_url': 'https://api.github.com/users/programmer-georgia/events{/privacy}', 'received_events_url': 'https://api.github.com/users/programmer-georgia/received_events', 'type': 'User', 'site_admin': False}, 'repo': {'id': 448401719, 'node_id': 'R_kgDOGroRNw', 'name': 'github-actions-for-ci', 'full_name': 'programmer-georgia/github-actions-for-ci', 'private': False, 'owner': {'login': 'programmer-georgia', 'id': 96337743, 'node_id': 'U_kgDOBb3_Tw', 'avatar_url': 'https://avatars.githubusercontent.com/u/96337743?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/programmer-georgia', 'html_url': 'https://github.com/programmer-georgia', 'followers_url': 'https://api.github.com/users/programmer-georgia/followers', 'following_url': 'https://api.github.com/users/programmer-georgia/following{/other_user}', 'gists_url': 'https://api.github.com/users/programmer-georgia/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/programmer-georgia/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/programmer-georgia/subscriptions', 'organizations_url': 'https://api.github.com/users/programmer-georgia/orgs', 'repos_url': 'https://api.github.com/users/programmer-georgia/repos', 'events_url': 'https://api.github.com/users/programmer-georgia/events{/privacy}', 'received_events_url': 'https://api.github.com/users/programmer-georgia/received_events', 'type': 'User', 'site_admin': False}, 'html_url': 'https://github.com/programmer-georgia/github-actions-for-ci', 'description': None, 'fork': False, 'url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci', 'forks_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/forks', 'keys_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/teams', 'hooks_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/hooks', 'issue_events_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/issues/events{/number}', 'events_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/events', 'assignees_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/assignees{/user}', 'branches_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/branches{/branch}', 'tags_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/tags', 'blobs_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/languages', 'stargazers_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/stargazers', 'contributors_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/contributors', 'subscribers_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/subscribers', 'subscription_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/subscription', 'commits_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/contents/{+path}', 'compare_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/merges', 'archive_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/downloads', 'issues_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/issues{/number}', 'pulls_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/labels{/name}', 'releases_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/releases{/id}', 'deployments_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/deployments', 'created_at': '2022-01-15T22:07:43Z', 'updated_at': '2022-01-15T22:07:48Z', 'pushed_at': '2022-02-02T14:23:28Z', 'git_url': 'git://github.com/programmer-georgia/github-actions-for-ci.git', 'ssh_url': 'git@github.com:programmer-georgia/github-actions-for-ci.git', 'clone_url': 'https://github.com/programmer-georgia/github-actions-for-ci.git', 'svn_url': 'https://github.com/programmer-georgia/github-actions-for-ci', 'homepage': 'https://lab.github.com/githubtraining/github-actions:-continuous-integration', 'size': 282, 'stargazers_count': 0, 'watchers_count': 0, 'language': 'JavaScript', 'has_issues': True, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 3, 'license': {'key': 'mit', 'name': 'MIT License', 'spdx_id': 'MIT', 'url': 'https://api.github.com/licenses/mit', 'node_id': 'MDc6TGljZW5zZTEz'}, 'allow_forking': True, 'is_template': False, 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 3, 'watchers': 0, 'default_branch': 'main'}}, 'base': {'label': 'programmer-georgia:main', 'ref': 'main', 'sha': '71232a170144f5d03c18f6ad1fad546a38072274', 'user': {'login': 'programmer-georgia', 'id': 96337743, 'node_id': 'U_kgDOBb3_Tw', 'avatar_url': 'https://avatars.githubusercontent.com/u/96337743?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/programmer-georgia', 'html_url': 'https://github.com/programmer-georgia', 'followers_url': 'https://api.github.com/users/programmer-georgia/followers', 'following_url': 'https://api.github.com/users/programmer-georgia/following{/other_user}', 'gists_url': 'https://api.github.com/users/programmer-georgia/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/programmer-georgia/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/programmer-georgia/subscriptions', 'organizations_url': 'https://api.github.com/users/programmer-georgia/orgs', 'repos_url': 'https://api.github.com/users/programmer-georgia/repos', 'events_url': 'https://api.github.com/users/programmer-georgia/events{/privacy}', 'received_events_url': 'https://api.github.com/users/programmer-georgia/received_events', 'type': 'User', 'site_admin': False}, 'repo': {'id': 448401719, 'node_id': 'R_kgDOGroRNw', 'name': 'github-actions-for-ci', 'full_name': 'programmer-georgia/github-actions-for-ci', 'private': False, 'owner': {'login': 'programmer-georgia', 'id': 96337743, 'node_id': 'U_kgDOBb3_Tw', 'avatar_url': 'https://avatars.githubusercontent.com/u/96337743?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/programmer-georgia', 'html_url': 'https://github.com/programmer-georgia', 'followers_url': 'https://api.github.com/users/programmer-georgia/followers', 'following_url': 'https://api.github.com/users/programmer-georgia/following{/other_user}', 'gists_url': 'https://api.github.com/users/programmer-georgia/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/programmer-georgia/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/programmer-georgia/subscriptions', 'organizations_url': 'https://api.github.com/users/programmer-georgia/orgs', 'repos_url': 'https://api.github.com/users/programmer-georgia/repos', 'events_url': 'https://api.github.com/users/programmer-georgia/events{/privacy}', 'received_events_url': 'https://api.github.com/users/programmer-georgia/received_events', 'type': 'User', 'site_admin': False}, 'html_url': 'https://github.com/programmer-georgia/github-actions-for-ci', 'description': None, 'fork': False, 'url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci', 'forks_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/forks', 'keys_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/teams', 'hooks_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/hooks', 'issue_events_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/issues/events{/number}', 'events_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/events', 'assignees_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/assignees{/user}', 'branches_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/branches{/branch}', 'tags_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/tags', 'blobs_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/languages', 'stargazers_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/stargazers', 'contributors_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/contributors', 'subscribers_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/subscribers', 'subscription_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/subscription', 'commits_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/contents/{+path}', 'compare_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/merges', 'archive_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/downloads', 'issues_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/issues{/number}', 'pulls_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/labels{/name}', 'releases_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/releases{/id}', 'deployments_url': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/deployments', 'created_at': '2022-01-15T22:07:43Z', 'updated_at': '2022-01-15T22:07:48Z', 'pushed_at': '2022-02-02T14:23:28Z', 'git_url': 'git://github.com/programmer-georgia/github-actions-for-ci.git', 'ssh_url': 'git@github.com:programmer-georgia/github-actions-for-ci.git', 'clone_url': 'https://github.com/programmer-georgia/github-actions-for-ci.git', 'svn_url': 'https://github.com/programmer-georgia/github-actions-for-ci', 'homepage': 'https://lab.github.com/githubtraining/github-actions:-continuous-integration', 'size': 282, 'stargazers_count': 0, 'watchers_count': 0, 'language': 'JavaScript', 'has_issues': True, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 3, 'license': {'key': 'mit', 'name': 'MIT License', 'spdx_id': 'MIT', 'url': 'https://api.github.com/licenses/mit', 'node_id': 'MDc6TGljZW5zZTEz'}, 'allow_forking': True, 'is_template': False, 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 3, 'watchers': 0, 'default_branch': 'main'}}, '_links': {'self': {'href': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/pulls/6'}, 'html': {'href': 'https://github.com/programmer-georgia/github-actions-for-ci/pull/6'}, 'issue': {'href': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/issues/6'}, 'comments': {'href': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/issues/6/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/pulls/6/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/pulls/6/commits'}, 'statuses': {'href': 'https://api.github.com/repos/programmer-georgia/github-actions-for-ci/statuses/3d8bdc3c3b1bd57f2295509b26c532c2dc26871d'}}, 'author_association': 'CONTRIBUTOR', 'auto_merge': None, 'active_lock_reason': None}}, 'public': True, 'created_at': '2022-02-02T14:23:31Z'}, {'id': '20038546662', 'type': 'PullRequestEvent', 'actor': {'id': 7466850, 'login': 'Wricken', 'display_login': 'Wricken', 'gravatar_id': '', 'url': 'https://api.github.com/users/Wricken', 'avatar_url': 'https://avatars.githubusercontent.com/u/7466850?'}, 'repo': {'id': 352591585, 'name': 'Wricken/node-test', 'url': 'https://api.github.com/repos/Wricken/node-test'}, 'payload': {'action': 'closed', 'number': 15, 'pull_request': {'url': 'https://api.github.com/repos/Wricken/node-test/pulls/15', 'id': 838358100, 'node_id': 'PR_kwDOFQQe4c4x-FRU', 'html_url': 'https://github.com/Wricken/node-test/pull/15', 'diff_url': 'https://github.com/Wricken/node-test/pull/15.diff', 'patch_url': 'https://github.com/Wricken/node-test/pull/15.patch', 'issue_url': 'https://api.github.com/repos/Wricken/node-test/issues/15', 'number': 15, 'state': 'closed', 'locked': False, 'title': 'Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "Update server.js"""""""""', 'user': {'login': 'Wricken', 'id': 7466850, 'node_id': 'MDQ6VXNlcjc0NjY4NTA=', 'avatar_url': 'https://avatars.githubusercontent.com/u/7466850?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/Wricken', 'html_url': 'https://github.com/Wricken', 'followers_url': 'https://api.github.com/users/Wricken/followers', 'following_url': 'https://api.github.com/users/Wricken/following{/other_user}', 'gists_url': 'https://api.github.com/users/Wricken/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/Wricken/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/Wricken/subscriptions', 'organizations_url': 'https://api.github.com/users/Wricken/orgs', 'repos_url': 'https://api.github.com/users/Wricken/repos', 'events_url': 'https://api.github.com/users/Wricken/events{/privacy}', 'received_events_url': 'https://api.github.com/users/Wricken/received_events', 'type': 'User', 'site_admin': False}, 'body': 'Reverts Wricken/node-test#14', 'created_at': '2022-02-02T14:23:14Z', 'updated_at': '2022-02-02T14:23:29Z', 'closed_at': '2022-02-02T14:23:29Z', 'merged_at': '2022-02-02T14:23:29Z', 'merge_commit_sha': '8011082e196461862c7690f351bdf5d3e8f01125', 'assignee': None, 'assignees': [], 'requested_reviewers': [], 'requested_teams': [], 'labels': [], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/Wricken/node-test/pulls/15/commits', 'review_comments_url': 'https://api.github.com/repos/Wricken/node-test/pulls/15/comments', 'review_comment_url': 'https://api.github.com/repos/Wricken/node-test/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/Wricken/node-test/issues/15/comments', 'statuses_url': 'https://api.github.com/repos/Wricken/node-test/statuses/6e20855d432dcabed8e2653d774152f55dc915c3', 'head': {'label': 'Wricken:revert-14-revert-13-revert-12-revert-11-revert-10-revert-9-revert-8-revert-7-revert-6-Wricken-patewffewfewfewch-1', 'ref': 'revert-14-revert-13-revert-12-revert-11-revert-10-revert-9-revert-8-revert-7-revert-6-Wricken-patewffewfewfewch-1', 'sha': '6e20855d432dcabed8e2653d774152f55dc915c3', 'user': {'login': 'Wricken', 'id': 7466850, 'node_id': 'MDQ6VXNlcjc0NjY4NTA=', 'avatar_url': 'https://avatars.githubusercontent.com/u/7466850?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/Wricken', 'html_url': 'https://github.com/Wricken', 'followers_url': 'https://api.github.com/users/Wricken/followers', 'following_url': 'https://api.github.com/users/Wricken/following{/other_user}', 'gists_url': 'https://api.github.com/users/Wricken/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/Wricken/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/Wricken/subscriptions', 'organizations_url': 'https://api.github.com/users/Wricken/orgs', 'repos_url': 'https://api.github.com/users/Wricken/repos', 'events_url': 'https://api.github.com/users/Wricken/events{/privacy}', 'received_events_url': 'https://api.github.com/users/Wricken/received_events', 'type': 'User', 'site_admin': False}, 'repo': {'id': 352591585, 'node_id': 'MDEwOlJlcG9zaXRvcnkzNTI1OTE1ODU=', 'name': 'node-test', 'full_name': 'Wricken/node-test', 'private': False, 'owner': {'login': 'Wricken', 'id': 7466850, 'node_id': 'MDQ6VXNlcjc0NjY4NTA=', 'avatar_url': 'https://avatars.githubusercontent.com/u/7466850?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/Wricken', 'html_url': 'https://github.com/Wricken', 'followers_url': 'https://api.github.com/users/Wricken/followers', 'following_url': 'https://api.github.com/users/Wricken/following{/other_user}', 'gists_url': 'https://api.github.com/users/Wricken/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/Wricken/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/Wricken/subscriptions', 'organizations_url': 'https://api.github.com/users/Wricken/orgs', 'repos_url': 'https://api.github.com/users/Wricken/repos', 'events_url': 'https://api.github.com/users/Wricken/events{/privacy}', 'received_events_url': 'https://api.github.com/users/Wricken/received_events', 'type': 'User', 'site_admin': False}, 'html_url': 'https://github.com/Wricken/node-test', 'description': None, 'fork': False, 'url': 'https://api.github.com/repos/Wricken/node-test', 'forks_url': 'https://api.github.com/repos/Wricken/node-test/forks', 'keys_url': 'https://api.github.com/repos/Wricken/node-test/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/Wricken/node-test/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/Wricken/node-test/teams', 'hooks_url': 'https://api.github.com/repos/Wricken/node-test/hooks', 'issue_events_url': 'https://api.github.com/repos/Wricken/node-test/issues/events{/number}', 'events_url': 'https://api.github.com/repos/Wricken/node-test/events', 'assignees_url': 'https://api.github.com/repos/Wricken/node-test/assignees{/user}', 'branches_url': 'https://api.github.com/repos/Wricken/node-test/branches{/branch}', 'tags_url': 'https://api.github.com/repos/Wricken/node-test/tags', 'blobs_url': 'https://api.github.com/repos/Wricken/node-test/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/Wricken/node-test/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/Wricken/node-test/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/Wricken/node-test/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/Wricken/node-test/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/Wricken/node-test/languages', 'stargazers_url': 'https://api.github.com/repos/Wricken/node-test/stargazers', 'contributors_url': 'https://api.github.com/repos/Wricken/node-test/contributors', 'subscribers_url': 'https://api.github.com/repos/Wricken/node-test/subscribers', 'subscription_url': 'https://api.github.com/repos/Wricken/node-test/subscription', 'commits_url': 'https://api.github.com/repos/Wricken/node-test/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/Wricken/node-test/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/Wricken/node-test/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/Wricken/node-test/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/Wricken/node-test/contents/{+path}', 'compare_url': 'https://api.github.com/repos/Wricken/node-test/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/Wricken/node-test/merges', 'archive_url': 'https://api.github.com/repos/Wricken/node-test/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/Wricken/node-test/downloads', 'issues_url': 'https://api.github.com/repos/Wricken/node-test/issues{/number}', 'pulls_url': 'https://api.github.com/repos/Wricken/node-test/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/Wricken/node-test/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/Wricken/node-test/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/Wricken/node-test/labels{/name}', 'releases_url': 'https://api.github.com/repos/Wricken/node-test/releases{/id}', 'deployments_url': 'https://api.github.com/repos/Wricken/node-test/deployments', 'created_at': '2021-03-29T09:44:50Z', 'updated_at': '2022-02-02T06:59:20Z', 'pushed_at': '2022-02-02T14:23:29Z', 'git_url': 'git://github.com/Wricken/node-test.git', 'ssh_url': 'git@github.com:Wricken/node-test.git', 'clone_url': 'https://github.com/Wricken/node-test.git', 'svn_url': 'https://github.com/Wricken/node-test', 'homepage': None, 'size': 706, 'stargazers_count': 0, 'watchers_count': 0, 'language': 'JavaScript', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': False, 'has_pages': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': None, 'allow_forking': True, 'is_template': False, 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'main'}}, 'base': {'label': 'Wricken:main', 'ref': 'main', 'sha': '6f72705905fdb65eb4f82fac14703ff199a69b7c', 'user': {'login': 'Wricken', 'id': 7466850, 'node_id': 'MDQ6VXNlcjc0NjY4NTA=', 'avatar_url': 'https://avatars.githubusercontent.com/u/7466850?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/Wricken', 'html_url': 'https://github.com/Wricken', 'followers_url': 'https://api.github.com/users/Wricken/followers', 'following_url': 'https://api.github.com/users/Wricken/following{/other_user}', 'gists_url': 'https://api.github.com/users/Wricken/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/Wricken/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/Wricken/subscriptions', 'organizations_url': 'https://api.github.com/users/Wricken/orgs', 'repos_url': 'https://api.github.com/users/Wricken/repos', 'events_url': 'https://api.github.com/users/Wricken/events{/privacy}', 'received_events_url': 'https://api.github.com/users/Wricken/received_events', 'type': 'User', 'site_admin': False}, 'repo': {'id': 352591585, 'node_id': 'MDEwOlJlcG9zaXRvcnkzNTI1OTE1ODU=', 'name': 'node-test', 'full_name': 'Wricken/node-test', 'private': False, 'owner': {'login': 'Wricken', 'id': 7466850, 'node_id': 'MDQ6VXNlcjc0NjY4NTA=', 'avatar_url': 'https://avatars.githubusercontent.com/u/7466850?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/Wricken', 'html_url': 'https://github.com/Wricken', 'followers_url': 'https://api.github.com/users/Wricken/followers', 'following_url': 'https://api.github.com/users/Wricken/following{/other_user}', 'gists_url': 'https://api.github.com/users/Wricken/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/Wricken/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/Wricken/subscriptions', 'organizations_url': 'https://api.github.com/users/Wricken/orgs', 'repos_url': 'https://api.github.com/users/Wricken/repos', 'events_url': 'https://api.github.com/users/Wricken/events{/privacy}', 'received_events_url': 'https://api.github.com/users/Wricken/received_events', 'type': 'User', 'site_admin': False}, 'html_url': 'https://github.com/Wricken/node-test', 'description': None, 'fork': False, 'url': 'https://api.github.com/repos/Wricken/node-test', 'forks_url': 'https://api.github.com/repos/Wricken/node-test/forks', 'keys_url': 'https://api.github.com/repos/Wricken/node-test/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/Wricken/node-test/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/Wricken/node-test/teams', 'hooks_url': 'https://api.github.com/repos/Wricken/node-test/hooks', 'issue_events_url': 'https://api.github.com/repos/Wricken/node-test/issues/events{/number}', 'events_url': 'https://api.github.com/repos/Wricken/node-test/events', 'assignees_url': 'https://api.github.com/repos/Wricken/node-test/assignees{/user}', 'branches_url': 'https://api.github.com/repos/Wricken/node-test/branches{/branch}', 'tags_url': 'https://api.github.com/repos/Wricken/node-test/tags', 'blobs_url': 'https://api.github.com/repos/Wricken/node-test/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/Wricken/node-test/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/Wricken/node-test/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/Wricken/node-test/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/Wricken/node-test/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/Wricken/node-test/languages', 'stargazers_url': 'https://api.github.com/repos/Wricken/node-test/stargazers', 'contributors_url': 'https://api.github.com/repos/Wricken/node-test/contributors', 'subscribers_url': 'https://api.github.com/repos/Wricken/node-test/subscribers', 'subscription_url': 'https://api.github.com/repos/Wricken/node-test/subscription', 'commits_url': 'https://api.github.com/repos/Wricken/node-test/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/Wricken/node-test/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/Wricken/node-test/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/Wricken/node-test/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/Wricken/node-test/contents/{+path}', 'compare_url': 'https://api.github.com/repos/Wricken/node-test/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/Wricken/node-test/merges', 'archive_url': 'https://api.github.com/repos/Wricken/node-test/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/Wricken/node-test/downloads', 'issues_url': 'https://api.github.com/repos/Wricken/node-test/issues{/number}', 'pulls_url': 'https://api.github.com/repos/Wricken/node-test/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/Wricken/node-test/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/Wricken/node-test/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/Wricken/node-test/labels{/name}', 'releases_url': 'https://api.github.com/repos/Wricken/node-test/releases{/id}', 'deployments_url': 'https://api.github.com/repos/Wricken/node-test/deployments', 'created_at': '2021-03-29T09:44:50Z', 'updated_at': '2022-02-02T06:59:20Z', 'pushed_at': '2022-02-02T14:23:29Z', 'git_url': 'git://github.com/Wricken/node-test.git', 'ssh_url': 'git@github.com:Wricken/node-test.git', 'clone_url': 'https://github.com/Wricken/node-test.git', 'svn_url': 'https://github.com/Wricken/node-test', 'homepage': None, 'size': 706, 'stargazers_count': 0, 'watchers_count': 0, 'language': 'JavaScript', 'has_issues': False, 'has_projects': False, 'has_downloads': True, 'has_wiki': False, 'has_pages': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': None, 'allow_forking': True, 'is_template': False, 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'main'}}, '_links': {'self': {'href': 'https://api.github.com/repos/Wricken/node-test/pulls/15'}, 'html': {'href': 'https://github.com/Wricken/node-test/pull/15'}, 'issue': {'href': 'https://api.github.com/repos/Wricken/node-test/issues/15'}, 'comments': {'href': 'https://api.github.com/repos/Wricken/node-test/issues/15/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/Wricken/node-test/pulls/15/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/Wricken/node-test/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/Wricken/node-test/pulls/15/commits'}, 'statuses': {'href': 'https://api.github.com/repos/Wricken/node-test/statuses/6e20855d432dcabed8e2653d774152f55dc915c3'}}, 'author_association': 'OWNER', 'auto_merge': None, 'active_lock_reason': None, 'merged': True, 'mergeable': None, 'rebaseable': None, 'mergeable_state': 'unknown', 'merged_by': {'login': 'Wricken', 'id': 7466850, 'node_id': 'MDQ6VXNlcjc0NjY4NTA=', 'avatar_url': 'https://avatars.githubusercontent.com/u/7466850?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/Wricken', 'html_url': 'https://github.com/Wricken', 'followers_url': 'https://api.github.com/users/Wricken/followers', 'following_url': 'https://api.github.com/users/Wricken/following{/other_user}', 'gists_url': 'https://api.github.com/users/Wricken/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/Wricken/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/Wricken/subscriptions', 'organizations_url': 'https://api.github.com/users/Wricken/orgs', 'repos_url': 'https://api.github.com/users/Wricken/repos', 'events_url': 'https://api.github.com/users/Wricken/events{/privacy}', 'received_events_url': 'https://api.github.com/users/Wricken/received_events', 'type': 'User', 'site_admin': False}, 'comments': 0, 'review_comments': 0, 'maintainer_can_modify': False, 'commits': 1, 'additions': 1, 'deletions': 1, 'changed_files': 1}}, 'public': True, 'created_at': '2022-02-02T14:23:31Z'}, {'id': '20038546668', 'type': 'PushEvent', 'actor': {'id': 33487926, 'login': 'KornevNikita', 'display_login': 'KornevNikita', 'gravatar_id': '', 'url': 'https://api.github.com/users/KornevNikita', 'avatar_url': 'https://avatars.githubusercontent.com/u/33487926?'}, 'repo': {'id': 362404309, 'name': 'KornevNikita/SPIRV-LLVM-Translator', 'url': 'https://api.github.com/repos/KornevNikita/SPIRV-LLVM-Translator'}, 'payload': {'push_id': 8993439039, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/printf', 'head': 'ecdd28c7ae73a15e45b4fa74aefcfa5c948aad7a', 'before': '8e421f5ba2d5a3ffd932cc88badf8a2d7c57ecb0', 'commits': [{'sha': 'ecdd28c7ae73a15e45b4fa74aefcfa5c948aad7a', 'author': {'email': 'nikita.kornev@intel.com', 'name': 'Nikita Kornev'}, 'message': 'Fix out-of-tree warning', 'distinct': True, 'url': 'https://api.github.com/repos/KornevNikita/SPIRV-LLVM-Translator/commits/ecdd28c7ae73a15e45b4fa74aefcfa5c948aad7a'}]}, 'public': True, 'created_at': '2022-02-02T14:23:31Z'}, {'id': '20038546475', 'type': 'PushEvent', 'actor': {'id': 61689499, 'login': 'Chariselyasa123', 'display_login': 'Chariselyasa123', 'gravatar_id': '', 'url': 'https://api.github.com/users/Chariselyasa123', 'avatar_url': 'https://avatars.githubusercontent.com/u/61689499?'}, 'repo': {'id': 442054872, 'name': 'Chariselyasa123/penghjauan-github', 'url': 'https://api.github.com/repos/Chariselyasa123/penghjauan-github'}, 'payload': {'push_id': 8993438927, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/master', 'head': 'a6a642068eb8e4805b2ce7adb2eef6029ba2b850', 'before': 'ac5ad154ce58207e1980907258f6816d020dfbe3', 'commits': [{'sha': 'a6a642068eb8e4805b2ce7adb2eef6029ba2b850', 'author': {'email': 'ahmad.charis@raharja.info', 'name': 'Chariselyasa123'}, 'message': 'feat: plant a tree 🎋', 'distinct': True, 'url': 'https://api.github.com/repos/Chariselyasa123/penghjauan-github/commits/a6a642068eb8e4805b2ce7adb2eef6029ba2b850'}]}, 'public': True, 'created_at': '2022-02-02T14:23:30Z'}, {'id': '20038546616', 'type': 'PullRequestReviewEvent', 'actor': {'id': 38854967, 'login': 'otc-zuul[bot]', 'display_login': 'otc-zuul', 'gravatar_id': '', 'url': 'https://api.github.com/users/otc-zuul[bot]', 'avatar_url': 'https://avatars.githubusercontent.com/u/38854967?'}, 'repo': {'id': 438200218, 'name': 'opentelekomcloud-infra/identity-deploy', 'url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy'}, 'payload': {'action': 'created', 'review': {'id': 870611929, 'node_id': 'PRR_kwDOGh5nms4z5HvZ', 'user': {'login': 'otc-zuul[bot]', 'id': 38854967, 'node_id': 'MDM6Qm90Mzg4NTQ5Njc=', 'avatar_url': 'https://avatars.githubusercontent.com/in/11628?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/otc-zuul%5Bbot%5D', 'html_url': 'https://github.com/apps/otc-zuul', 'followers_url': 'https://api.github.com/users/otc-zuul%5Bbot%5D/followers', 'following_url': 'https://api.github.com/users/otc-zuul%5Bbot%5D/following{/other_user}', 'gists_url': 'https://api.github.com/users/otc-zuul%5Bbot%5D/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/otc-zuul%5Bbot%5D/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/otc-zuul%5Bbot%5D/subscriptions', 'organizations_url': 'https://api.github.com/users/otc-zuul%5Bbot%5D/orgs', 'repos_url': 'https://api.github.com/users/otc-zuul%5Bbot%5D/repos', 'events_url': 'https://api.github.com/users/otc-zuul%5Bbot%5D/events{/privacy}', 'received_events_url': 'https://api.github.com/users/otc-zuul%5Bbot%5D/received_events', 'type': 'Bot', 'site_admin': False}, 'body': '', 'commit_id': '3673ec03da18e60a697368ef16d28c4b89e54228', 'submitted_at': '2022-02-02T14:23:30Z', 'state': 'approved', 'html_url': 'https://github.com/opentelekomcloud-infra/identity-deploy/pull/16#pullrequestreview-870611929', 'pull_request_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/pulls/16', 'author_association': 'NONE', '_links': {'html': {'href': 'https://github.com/opentelekomcloud-infra/identity-deploy/pull/16#pullrequestreview-870611929'}, 'pull_request': {'href': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/pulls/16'}}}, 'pull_request': {'url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/pulls/16', 'id': 838338863, 'node_id': 'PR_kwDOGh5nms4x-Akv', 'html_url': 'https://github.com/opentelekomcloud-infra/identity-deploy/pull/16', 'diff_url': 'https://github.com/opentelekomcloud-infra/identity-deploy/pull/16.diff', 'patch_url': 'https://github.com/opentelekomcloud-infra/identity-deploy/pull/16.patch', 'issue_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/issues/16', 'number': 16, 'state': 'open', 'locked': False, 'title': 'Add deeper zuul itegration', 'user': {'login': 'outcatcher', 'id': 8591561, 'node_id': 'MDQ6VXNlcjg1OTE1NjE=', 'avatar_url': 'https://avatars.githubusercontent.com/u/8591561?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/outcatcher', 'html_url': 'https://github.com/outcatcher', 'followers_url': 'https://api.github.com/users/outcatcher/followers', 'following_url': 'https://api.github.com/users/outcatcher/following{/other_user}', 'gists_url': 'https://api.github.com/users/outcatcher/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/outcatcher/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/outcatcher/subscriptions', 'organizations_url': 'https://api.github.com/users/outcatcher/orgs', 'repos_url': 'https://api.github.com/users/outcatcher/repos', 'events_url': 'https://api.github.com/users/outcatcher/events{/privacy}', 'received_events_url': 'https://api.github.com/users/outcatcher/received_events', 'type': 'User', 'site_admin': False}, 'body': 'Add two new zuul jobs:\r\n- `tox-functional-identity`\r\n- `golang-make-functional-identity`\r\n\r\nInheriting from `tox-functional` and `golang-make-functional` jobs respectively and deploying identity service on OTC VM.', 'created_at': '2022-02-02T14:03:28Z', 'updated_at': '2022-02-02T14:23:30Z', 'closed_at': None, 'merged_at': None, 'merge_commit_sha': 'd03fd4ec046c634c71ac82d2184e600825662cbe', 'assignee': None, 'assignees': [], 'requested_reviewers': [{'login': 'Polina-Gubina', 'id': 33940358, 'node_id': 'MDQ6VXNlcjMzOTQwMzU4', 'avatar_url': 'https://avatars.githubusercontent.com/u/33940358?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/Polina-Gubina', 'html_url': 'https://github.com/Polina-Gubina', 'followers_url': 'https://api.github.com/users/Polina-Gubina/followers', 'following_url': 'https://api.github.com/users/Polina-Gubina/following{/other_user}', 'gists_url': 'https://api.github.com/users/Polina-Gubina/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/Polina-Gubina/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/Polina-Gubina/subscriptions', 'organizations_url': 'https://api.github.com/users/Polina-Gubina/orgs', 'repos_url': 'https://api.github.com/users/Polina-Gubina/repos', 'events_url': 'https://api.github.com/users/Polina-Gubina/events{/privacy}', 'received_events_url': 'https://api.github.com/users/Polina-Gubina/received_events', 'type': 'User', 'site_admin': False}], 'requested_teams': [], 'labels': [{'id': 3640932468, 'node_id': 'LA_kwDOGh5nms7ZBDh0', 'url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/labels/post', 'name': 'post', 'color': 'FEF2C0', 'default': False, 'description': 'Execute check-post pipeline'}], 'milestone': None, 'draft': False, 'commits_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/pulls/16/commits', 'review_comments_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/pulls/16/comments', 'review_comment_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/pulls/comments{/number}', 'comments_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/issues/16/comments', 'statuses_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/statuses/3673ec03da18e60a697368ef16d28c4b89e54228', 'head': {'label': 'opentelekomcloud-infra:zuul-identity', 'ref': 'zuul-identity', 'sha': '3673ec03da18e60a697368ef16d28c4b89e54228', 'user': {'login': 'opentelekomcloud-infra', 'id': 45656414, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjQ1NjU2NDE0', 'avatar_url': 'https://avatars.githubusercontent.com/u/45656414?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/opentelekomcloud-infra', 'html_url': 'https://github.com/opentelekomcloud-infra', 'followers_url': 'https://api.github.com/users/opentelekomcloud-infra/followers', 'following_url': 'https://api.github.com/users/opentelekomcloud-infra/following{/other_user}', 'gists_url': 'https://api.github.com/users/opentelekomcloud-infra/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/opentelekomcloud-infra/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/opentelekomcloud-infra/subscriptions', 'organizations_url': 'https://api.github.com/users/opentelekomcloud-infra/orgs', 'repos_url': 'https://api.github.com/users/opentelekomcloud-infra/repos', 'events_url': 'https://api.github.com/users/opentelekomcloud-infra/events{/privacy}', 'received_events_url': 'https://api.github.com/users/opentelekomcloud-infra/received_events', 'type': 'Organization', 'site_admin': False}, 'repo': {'id': 438200218, 'node_id': 'R_kgDOGh5nmg', 'name': 'identity-deploy', 'full_name': 'opentelekomcloud-infra/identity-deploy', 'private': False, 'owner': {'login': 'opentelekomcloud-infra', 'id': 45656414, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjQ1NjU2NDE0', 'avatar_url': 'https://avatars.githubusercontent.com/u/45656414?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/opentelekomcloud-infra', 'html_url': 'https://github.com/opentelekomcloud-infra', 'followers_url': 'https://api.github.com/users/opentelekomcloud-infra/followers', 'following_url': 'https://api.github.com/users/opentelekomcloud-infra/following{/other_user}', 'gists_url': 'https://api.github.com/users/opentelekomcloud-infra/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/opentelekomcloud-infra/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/opentelekomcloud-infra/subscriptions', 'organizations_url': 'https://api.github.com/users/opentelekomcloud-infra/orgs', 'repos_url': 'https://api.github.com/users/opentelekomcloud-infra/repos', 'events_url': 'https://api.github.com/users/opentelekomcloud-infra/events{/privacy}', 'received_events_url': 'https://api.github.com/users/opentelekomcloud-infra/received_events', 'type': 'Organization', 'site_admin': False}, 'html_url': 'https://github.com/opentelekomcloud-infra/identity-deploy', 'description': 'Ansible playbook to deploy stand-alone OpenStack keystone service', 'fork': True, 'url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy', 'forks_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/forks', 'keys_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/teams', 'hooks_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/hooks', 'issue_events_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/issues/events{/number}', 'events_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/events', 'assignees_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/assignees{/user}', 'branches_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/branches{/branch}', 'tags_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/tags', 'blobs_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/languages', 'stargazers_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/stargazers', 'contributors_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/contributors', 'subscribers_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/subscribers', 'subscription_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/subscription', 'commits_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/contents/{+path}', 'compare_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/merges', 'archive_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/downloads', 'issues_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/issues{/number}', 'pulls_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/labels{/name}', 'releases_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/releases{/id}', 'deployments_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/deployments', 'created_at': '2021-12-14T09:55:15Z', 'updated_at': '2021-12-29T10:33:01Z', 'pushed_at': '2022-02-02T14:20:41Z', 'git_url': 'git://github.com/opentelekomcloud-infra/identity-deploy.git', 'ssh_url': 'git@github.com:opentelekomcloud-infra/identity-deploy.git', 'clone_url': 'https://github.com/opentelekomcloud-infra/identity-deploy.git', 'svn_url': 'https://github.com/opentelekomcloud-infra/identity-deploy', 'homepage': '', 'size': 48, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': True, 'has_projects': False, 'has_downloads': True, 'has_wiki': False, 'has_pages': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 1, 'license': {'key': 'apache-2.0', 'name': 'Apache License 2.0', 'spdx_id': 'Apache-2.0', 'url': 'https://api.github.com/licenses/apache-2.0', 'node_id': 'MDc6TGljZW5zZTI='}, 'allow_forking': True, 'is_template': False, 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 1, 'watchers': 0, 'default_branch': 'main'}}, 'base': {'label': 'opentelekomcloud-infra:main', 'ref': 'main', 'sha': '9f3646c241294deb375d1375d017f42498e29b2c', 'user': {'login': 'opentelekomcloud-infra', 'id': 45656414, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjQ1NjU2NDE0', 'avatar_url': 'https://avatars.githubusercontent.com/u/45656414?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/opentelekomcloud-infra', 'html_url': 'https://github.com/opentelekomcloud-infra', 'followers_url': 'https://api.github.com/users/opentelekomcloud-infra/followers', 'following_url': 'https://api.github.com/users/opentelekomcloud-infra/following{/other_user}', 'gists_url': 'https://api.github.com/users/opentelekomcloud-infra/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/opentelekomcloud-infra/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/opentelekomcloud-infra/subscriptions', 'organizations_url': 'https://api.github.com/users/opentelekomcloud-infra/orgs', 'repos_url': 'https://api.github.com/users/opentelekomcloud-infra/repos', 'events_url': 'https://api.github.com/users/opentelekomcloud-infra/events{/privacy}', 'received_events_url': 'https://api.github.com/users/opentelekomcloud-infra/received_events', 'type': 'Organization', 'site_admin': False}, 'repo': {'id': 438200218, 'node_id': 'R_kgDOGh5nmg', 'name': 'identity-deploy', 'full_name': 'opentelekomcloud-infra/identity-deploy', 'private': False, 'owner': {'login': 'opentelekomcloud-infra', 'id': 45656414, 'node_id': 'MDEyOk9yZ2FuaXphdGlvbjQ1NjU2NDE0', 'avatar_url': 'https://avatars.githubusercontent.com/u/45656414?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/opentelekomcloud-infra', 'html_url': 'https://github.com/opentelekomcloud-infra', 'followers_url': 'https://api.github.com/users/opentelekomcloud-infra/followers', 'following_url': 'https://api.github.com/users/opentelekomcloud-infra/following{/other_user}', 'gists_url': 'https://api.github.com/users/opentelekomcloud-infra/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/opentelekomcloud-infra/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/opentelekomcloud-infra/subscriptions', 'organizations_url': 'https://api.github.com/users/opentelekomcloud-infra/orgs', 'repos_url': 'https://api.github.com/users/opentelekomcloud-infra/repos', 'events_url': 'https://api.github.com/users/opentelekomcloud-infra/events{/privacy}', 'received_events_url': 'https://api.github.com/users/opentelekomcloud-infra/received_events', 'type': 'Organization', 'site_admin': False}, 'html_url': 'https://github.com/opentelekomcloud-infra/identity-deploy', 'description': 'Ansible playbook to deploy stand-alone OpenStack keystone service', 'fork': True, 'url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy', 'forks_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/forks', 'keys_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/teams', 'hooks_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/hooks', 'issue_events_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/issues/events{/number}', 'events_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/events', 'assignees_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/assignees{/user}', 'branches_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/branches{/branch}', 'tags_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/tags', 'blobs_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/languages', 'stargazers_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/stargazers', 'contributors_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/contributors', 'subscribers_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/subscribers', 'subscription_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/subscription', 'commits_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/contents/{+path}', 'compare_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/merges', 'archive_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/downloads', 'issues_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/issues{/number}', 'pulls_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/labels{/name}', 'releases_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/releases{/id}', 'deployments_url': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/deployments', 'created_at': '2021-12-14T09:55:15Z', 'updated_at': '2021-12-29T10:33:01Z', 'pushed_at': '2022-02-02T14:20:41Z', 'git_url': 'git://github.com/opentelekomcloud-infra/identity-deploy.git', 'ssh_url': 'git@github.com:opentelekomcloud-infra/identity-deploy.git', 'clone_url': 'https://github.com/opentelekomcloud-infra/identity-deploy.git', 'svn_url': 'https://github.com/opentelekomcloud-infra/identity-deploy', 'homepage': '', 'size': 48, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': True, 'has_projects': False, 'has_downloads': True, 'has_wiki': False, 'has_pages': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 1, 'license': {'key': 'apache-2.0', 'name': 'Apache License 2.0', 'spdx_id': 'Apache-2.0', 'url': 'https://api.github.com/licenses/apache-2.0', 'node_id': 'MDc6TGljZW5zZTI='}, 'allow_forking': True, 'is_template': False, 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 1, 'watchers': 0, 'default_branch': 'main'}}, '_links': {'self': {'href': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/pulls/16'}, 'html': {'href': 'https://github.com/opentelekomcloud-infra/identity-deploy/pull/16'}, 'issue': {'href': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/issues/16'}, 'comments': {'href': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/issues/16/comments'}, 'review_comments': {'href': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/pulls/16/comments'}, 'review_comment': {'href': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/pulls/comments{/number}'}, 'commits': {'href': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/pulls/16/commits'}, 'statuses': {'href': 'https://api.github.com/repos/opentelekomcloud-infra/identity-deploy/statuses/3673ec03da18e60a697368ef16d28c4b89e54228'}}, 'author_association': 'MEMBER', 'auto_merge': None, 'active_lock_reason': None}}, 'public': True, 'created_at': '2022-02-02T14:23:31Z', 'org': {'id': 45656414, 'login': 'opentelekomcloud-infra', 'gravatar_id': '', 'url': 'https://api.github.com/orgs/opentelekomcloud-infra', 'avatar_url': 'https://avatars.githubusercontent.com/u/45656414?'}}, {'id': '20038546650', 'type': 'PushEvent', 'actor': {'id': 41898282, 'login': 'github-actions[bot]', 'display_login': 'github-actions', 'gravatar_id': '', 'url': 'https://api.github.com/users/github-actions[bot]', 'avatar_url': 'https://avatars.githubusercontent.com/u/41898282?'}, 'repo': {'id': 340782702, 'name': 'jasoncartwright/bbcrss', 'url': 'https://api.github.com/repos/jasoncartwright/bbcrss'}, 'payload': {'push_id': 8993439229, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/main', 'head': 'b6e924e03a85ef8e57fbd32ae19e815ccaec4ece', 'before': '7f96899e2f2e368f21a0899e87e6454d6bd172d5', 'commits': [{'sha': 'b6e924e03a85ef8e57fbd32ae19e815ccaec4ece', 'author': {'email': 'actions@users.noreply.github.com', 'name': 'Automated'}, 'message': 'Latest RSS: Wed Feb  2 14:23:29 UTC 2022', 'distinct': True, 'url': 'https://api.github.com/repos/jasoncartwright/bbcrss/commits/b6e924e03a85ef8e57fbd32ae19e815ccaec4ece'}]}, 'public': True, 'created_at': '2022-02-02T14:23:31Z'}, {'id': '20038546315', 'type': 'PushEvent', 'actor': {'id': 34437496, 'login': 'DanielPDWalker', 'display_login': 'DanielPDWalker', 'gravatar_id': '', 'url': 'https://api.github.com/users/DanielPDWalker', 'avatar_url': 'https://avatars.githubusercontent.com/u/34437496?'}, 'repo': {'id': 436636451, 'name': 'Matatika/dbt-tap-meltano', 'url': 'https://api.github.com/repos/Matatika/dbt-tap-meltano'}, 'payload': {'push_id': 8993439045, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/master', 'head': '2d6ba880189ba8507dd890bc015939df87ad2f2d', 'before': '6d8d1f6f5a310cf5e9258dc079c2dd2baaaaa24c', 'commits': [{'sha': '2d6ba880189ba8507dd890bc015939df87ad2f2d', 'author': {'email': 'danielpdwalker@gmail.com', 'name': 'danielpdwalker'}, 'message': 'Bumped version to 0.1.1', 'distinct': True, 'url': 'https://api.github.com/repos/Matatika/dbt-tap-meltano/commits/2d6ba880189ba8507dd890bc015939df87ad2f2d'}]}, 'public': True, 'created_at': '2022-02-02T14:23:30Z', 'org': {'id': 63709023, 'login': 'Matatika', 'gravatar_id': '', 'url': 'https://api.github.com/orgs/Matatika', 'avatar_url': 'https://avatars.githubusercontent.com/u/63709023?'}}, {'id': '20038546613', 'type': 'CreateEvent', 'actor': {'id': 13369065, 'login': 'appinlet', 'display_login': 'appinlet', 'gravatar_id': '', 'url': 'https://api.github.com/users/appinlet', 'avatar_url': 'https://avatars.githubusercontent.com/u/13369065?'}, 'repo': {'id': 215828308, 'name': 'DPO-Group/DPO_WooCommerce', 'url': 'https://api.github.com/repos/DPO-Group/DPO_WooCommerce'}, 'payload': {'ref': 'v1.1.1', 'ref_type': 'tag', 'master_branch': 'master', 'description': 'This is the DPO Group plugin for WooCommerce.', 'pusher_type': 'user'}, 'public': True, 'created_at': '2022-02-02T14:23:31Z', 'org': {'id': 55230053, 'login': 'DPO-Group', 'gravatar_id': '', 'url': 'https://api.github.com/orgs/DPO-Group', 'avatar_url': 'https://avatars.githubusercontent.com/u/55230053?'}}, {'id': '20038545409', 'type': 'ForkEvent', 'actor': {'id': 71681815, 'login': 'LaudateCorpus1', 'display_login': 'LaudateCorpus1', 'gravatar_id': '', 'url': 'https://api.github.com/users/LaudateCorpus1', 'avatar_url': 'https://avatars.githubusercontent.com/u/71681815?'}, 'repo': {'id': 42317389, 'name': 'discord/node-spellchecker', 'url': 'https://api.github.com/repos/discord/node-spellchecker'}, 'payload': {'forkee': {'id': 454805289, 'node_id': 'R_kgDOGxvHKQ', 'name': 'node-spellchecker', 'full_name': 'LaudateCorpus1/node-spellchecker', 'private': False, 'owner': {'login': 'LaudateCorpus1', 'id': 71681815, 'node_id': 'MDQ6VXNlcjcxNjgxODE1', 'avatar_url': 'https://avatars.githubusercontent.com/u/71681815?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/LaudateCorpus1', 'html_url': 'https://github.com/LaudateCorpus1', 'followers_url': 'https://api.github.com/users/LaudateCorpus1/followers', 'following_url': 'https://api.github.com/users/LaudateCorpus1/following{/other_user}', 'gists_url': 'https://api.github.com/users/LaudateCorpus1/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/LaudateCorpus1/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/LaudateCorpus1/subscriptions', 'organizations_url': 'https://api.github.com/users/LaudateCorpus1/orgs', 'repos_url': 'https://api.github.com/users/LaudateCorpus1/repos', 'events_url': 'https://api.github.com/users/LaudateCorpus1/events{/privacy}', 'received_events_url': 'https://api.github.com/users/LaudateCorpus1/received_events', 'type': 'User', 'site_admin': False}, 'html_url': 'https://github.com/LaudateCorpus1/node-spellchecker', 'description': 'SpellChecker Node Module', 'fork': True, 'url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker', 'forks_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/forks', 'keys_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/keys{/key_id}', 'collaborators_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/collaborators{/collaborator}', 'teams_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/teams', 'hooks_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/hooks', 'issue_events_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/issues/events{/number}', 'events_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/events', 'assignees_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/assignees{/user}', 'branches_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/branches{/branch}', 'tags_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/tags', 'blobs_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/git/blobs{/sha}', 'git_tags_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/git/tags{/sha}', 'git_refs_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/git/refs{/sha}', 'trees_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/git/trees{/sha}', 'statuses_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/statuses/{sha}', 'languages_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/languages', 'stargazers_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/stargazers', 'contributors_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/contributors', 'subscribers_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/subscribers', 'subscription_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/subscription', 'commits_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/commits{/sha}', 'git_commits_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/git/commits{/sha}', 'comments_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/comments{/number}', 'issue_comment_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/issues/comments{/number}', 'contents_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/contents/{+path}', 'compare_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/compare/{base}...{head}', 'merges_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/merges', 'archive_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/{archive_format}{/ref}', 'downloads_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/downloads', 'issues_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/issues{/number}', 'pulls_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/pulls{/number}', 'milestones_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/milestones{/number}', 'notifications_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/notifications{?since,all,participating}', 'labels_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/labels{/name}', 'releases_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/releases{/id}', 'deployments_url': 'https://api.github.com/repos/LaudateCorpus1/node-spellchecker/deployments', 'created_at': '2022-02-02T14:23:24Z', 'updated_at': '2021-04-28T21:28:49Z', 'pushed_at': '2019-07-31T22:56:22Z', 'git_url': 'git://github.com/LaudateCorpus1/node-spellchecker.git', 'ssh_url': 'git@github.com:LaudateCorpus1/node-spellchecker.git', 'clone_url': 'https://github.com/LaudateCorpus1/node-spellchecker.git', 'svn_url': 'https://github.com/LaudateCorpus1/node-spellchecker', 'homepage': 'http://atom.github.io/node-spellchecker', 'size': 2623, 'stargazers_count': 0, 'watchers_count': 0, 'language': None, 'has_issues': False, 'has_projects': True, 'has_downloads': True, 'has_wiki': True, 'has_pages': False, 'forks_count': 0, 'mirror_url': None, 'archived': False, 'disabled': False, 'open_issues_count': 0, 'license': {'key': 'mit', 'name': 'MIT License', 'spdx_id': 'MIT', 'url': 'https://api.github.com/licenses/mit', 'node_id': 'MDc6TGljZW5zZTEz'}, 'allow_forking': True, 'is_template': False, 'topics': [], 'visibility': 'public', 'forks': 0, 'open_issues': 0, 'watchers': 0, 'default_branch': 'master', 'public': True}}, 'public': True, 'created_at': '2022-02-02T14:23:27Z', 'org': {'id': 1965106, 'login': 'discord', 'gravatar_id': '', 'url': 'https://api.github.com/orgs/discord', 'avatar_url': 'https://avatars.githubusercontent.com/u/1965106?'}}, {'id': '20038546576', 'type': 'PushEvent', 'actor': {'id': 20691392, 'login': 'beckymarques', 'display_login': 'beckymarques', 'gravatar_id': '', 'url': 'https://api.github.com/users/beckymarques', 'avatar_url': 'https://avatars.githubusercontent.com/u/20691392?'}, 'repo': {'id': 445614110, 'name': 'colmeiaperformance/revitta', 'url': 'https://api.github.com/repos/colmeiaperformance/revitta'}, 'payload': {'push_id': 8993439091, 'size': 2, 'distinct_size': 0, 'ref': 'refs/heads/acf-php', 'head': 'e797634ff1538109056e51b1f221c6e2d49cef44', 'before': '53676bd520529cb7a2cb56d5b17d87a96ff624df', 'commits': [{'sha': 'e843b82907ca47ca26bf72643dc439e18721c448', 'author': {'email': 'brunarafaelav@outlook.com', 'name': 'brunarafaela'}, 'message': 'Add form style', 'distinct': False, 'url': 'https://api.github.com/repos/colmeiaperformance/revitta/commits/e843b82907ca47ca26bf72643dc439e18721c448'}, {'sha': 'e797634ff1538109056e51b1f221c6e2d49cef44', 'author': {'email': 'becky.marques@colmeiaperformance.com.br', 'name': 'Becky Marques'}, 'message': 'Update page-home.php', 'distinct': False, 'url': 'https://api.github.com/repos/colmeiaperformance/revitta/commits/e797634ff1538109056e51b1f221c6e2d49cef44'}]}, 'public': True, 'created_at': '2022-02-02T14:23:30Z', 'org': {'id': 60509413, 'login': 'colmeiaperformance', 'gravatar_id': '', 'url': 'https://api.github.com/orgs/colmeiaperformance', 'avatar_url': 'https://avatars.githubusercontent.com/u/60509413?'}}, {'id': '20038546558', 'type': 'CreateEvent', 'actor': {'id': 95173046, 'login': 'Guigzouz', 'display_login': 'Guigzouz', 'gravatar_id': '', 'url': 'https://api.github.com/users/Guigzouz', 'avatar_url': 'https://avatars.githubusercontent.com/u/95173046?'}, 'repo': {'id': 454804844, 'name': 'Guigzouz/Guigzouz', 'url': 'https://api.github.com/repos/Guigzouz/Guigzouz'}, 'payload': {'ref': 'main', 'ref_type': 'branch', 'master_branch': 'main', 'description': 'Config files for my GitHub profile.', 'pusher_type': 'user'}, 'public': True, 'created_at': '2022-02-02T14:23:30Z'}, {'id': '20038545401', 'type': 'PushEvent', 'actor': {'id': 70335472, 'login': 'FinnMal', 'display_login': 'FinnMal', 'gravatar_id': '', 'url': 'https://api.github.com/users/FinnMal', 'avatar_url': 'https://avatars.githubusercontent.com/u/70335472?'}, 'repo': {'id': 454804237, 'name': 'FinnMal/CryptopusBrowserGame', 'url': 'https://api.github.com/repos/FinnMal/CryptopusBrowserGame'}, 'payload': {'push_id': 8993438553, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/master', 'head': '93cf7c05835388799137a7f4d49dd7fce9b9f6da', 'before': 'bfd488bca2c4681abd88148ae60bce66a2b98993', 'commits': [{'sha': '93cf7c05835388799137a7f4d49dd7fce9b9f6da', 'author': {'email': 'finn@malkus.de', 'name': 'Finn Malkus'}, 'message': 'removed useless comments', 'distinct': True, 'url': 'https://api.github.com/repos/FinnMal/CryptopusBrowserGame/commits/93cf7c05835388799137a7f4d49dd7fce9b9f6da'}]}, 'public': True, 'created_at': '2022-02-02T14:23:27Z'}, {'id': '20038546574', 'type': 'PushEvent', 'actor': {'id': 55398995, 'login': 'Josh-Cena', 'display_login': 'Josh-Cena', 'gravatar_id': '', 'url': 'https://api.github.com/users/Josh-Cena', 'avatar_url': 'https://avatars.githubusercontent.com/u/55398995?'}, 'repo': {'id': 94911145, 'name': 'facebook/docusaurus', 'url': 'https://api.github.com/repos/facebook/docusaurus'}, 'payload': {'push_id': 8993439048, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/jc/read-category-metadata-aot', 'head': 'c81aee461f8ee44be5f4e1a4c960c1c1f9183850', 'before': 'a8f80488dff7f97023c1ca8f1d5d4d052c0ab3ce', 'commits': [{'sha': 'c81aee461f8ee44be5f4e1a4c960c1c1f9183850', 'author': {'email': 'sidachen2003@gmail.com', 'name': 'Joshua Chen'}, 'message': 'fix Windows...', 'distinct': True, 'url': 'https://api.github.com/repos/facebook/docusaurus/commits/c81aee461f8ee44be5f4e1a4c960c1c1f9183850'}]}, 'public': True, 'created_at': '2022-02-02T14:23:30Z', 'org': {'id': 69631, 'login': 'facebook', 'gravatar_id': '', 'url': 'https://api.github.com/orgs/facebook', 'avatar_url': 'https://avatars.githubusercontent.com/u/69631?'}}, {'id': '20038546549', 'type': 'PushEvent', 'actor': {'id': 88927411, 'login': 'pKorsholm', 'display_login': 'pKorsholm', 'gravatar_id': '', 'url': 'https://api.github.com/users/pKorsholm', 'avatar_url': 'https://avatars.githubusercontent.com/u/88927411?'}, 'repo': {'id': 271286876, 'name': 'medusajs/admin', 'url': 'https://api.github.com/repos/medusajs/admin'}, 'payload': {'push_id': 8993439042, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/feat/revamp', 'head': '6f2f2f0dcc04e97fb9b8a0242618b262a4ae3fcf', 'before': '8da6d03f865e0f8cdb3c1b7550585f8d67881f5a', 'commits': [{'sha': '6f2f2f0dcc04e97fb9b8a0242618b262a4ae3fcf', 'author': {'email': '88927411+pKorsholm@users.noreply.github.com', 'name': 'Philip Korsholm'}, 'message': 'Feat/revamp rma request return (#273)\n\n* progress on new components\r\n\r\n* progress\r\n\r\n* added responsive denomination grid\r\n\r\n* changed to molecule\r\n\r\n* progress\r\n\r\n* requested changes\r\n\r\n* update\r\n\r\n* fixed currencies\r\n\r\n* added new component to region settings + minor fixes to settings and story\r\n\r\n* requested changes\r\n\r\n* fixed story\r\n\r\n* removed comment\r\n\r\n* fix type\r\n\r\n* fix merge conflicts\r\n\r\n* initial returns modal\r\n\r\n* update create return modal\r\n\r\n* hotfix currency input\r\n\r\n* remove comments and console.logs\r\n\r\n* add shipping total\r\n\r\n* refactor return request rma\r\n\r\n* typescript cleanup\r\n\r\n* receive menu\r\n\r\n* remove unused button for selecting return reason\r\n\r\n* add select product table\r\n\r\n* switch to object based "toReturn" instead of array to accomodate extension with return reasons\r\n\r\n* create sub modal functionality\r\n\r\n* modal update for sub modal\r\n\r\n* animations config\r\n\r\n* layered modal\r\n\r\n* reset screens on close\r\n\r\n* final touches on select return reason\r\n\r\n* pr feedback\r\n\r\n* use hooks for request return\r\n\r\n* upgrade admin hooks\r\n\r\n* fix reason selection\r\n\r\nCo-authored-by: Kasper <kasper@medusa-commerce.com>\r\nCo-authored-by: olivermrbl <oliver@mrbltech.com>', 'distinct': True, 'url': 'https://api.github.com/repos/medusajs/admin/commits/6f2f2f0dcc04e97fb9b8a0242618b262a4ae3fcf'}]}, 'public': True, 'created_at': '2022-02-02T14:23:30Z', 'org': {'id': 62591822, 'login': 'medusajs', 'gravatar_id': '', 'url': 'https://api.github.com/orgs/medusajs', 'avatar_url': 'https://avatars.githubusercontent.com/u/62591822?'}}, {'id': '20038546598', 'type': 'PushEvent', 'actor': {'id': 67910697, 'login': 'cablemp5', 'display_login': 'cablemp5', 'gravatar_id': '', 'url': 'https://api.github.com/users/cablemp5', 'avatar_url': 'https://avatars.githubusercontent.com/u/67910697?'}, 'repo': {'id': 454228778, 'name': 'cablemp5/wordlebutshit', 'url': 'https://api.github.com/repos/cablemp5/wordlebutshit'}, 'payload': {'push_id': 8993439100, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/main', 'head': '9f66c5dc17b9e9609e698731a5e75ba3dbe1bae0', 'before': '2469e23be7a96ee7c3c59ec7af0dc416656fd36f', 'commits': [{'sha': '9f66c5dc17b9e9609e698731a5e75ba3dbe1bae0', 'author': {'email': 'cmikec12@gmail.com', 'name': 'Caleb Collins'}, 'message': 'Update README.md', 'distinct': True, 'url': 'https://api.github.com/repos/cablemp5/wordlebutshit/commits/9f66c5dc17b9e9609e698731a5e75ba3dbe1bae0'}]}, 'public': True, 'created_at': '2022-02-02T14:23:31Z'}, {'id': '20038546568', 'type': 'PushEvent', 'actor': {'id': 41898282, 'login': 'github-actions[bot]', 'display_login': 'github-actions', 'gravatar_id': '', 'url': 'https://api.github.com/users/github-actions[bot]', 'avatar_url': 'https://avatars.githubusercontent.com/u/41898282?'}, 'repo': {'id': 436332813, 'name': 'gdlcf88/gdlcf88', 'url': 'https://api.github.com/repos/gdlcf88/gdlcf88'}, 'payload': {'push_id': 8993439187, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/main', 'head': '11ff7aac50ad43a3fade75d97aead8b11a75a5d1', 'before': 'eaf23e20ccff80bc19cd3bbc0b17967b9d8c51a9', 'commits': [{'sha': '11ff7aac50ad43a3fade75d97aead8b11a75a5d1', 'author': {'email': '41898282+github-actions[bot]@users.noreply.github.com', 'name': 'github-actions[bot]'}, 'message': 'Update github-metrics.svg - [Skip GitHub Action]', 'distinct': True, 'url': 'https://api.github.com/repos/gdlcf88/gdlcf88/commits/11ff7aac50ad43a3fade75d97aead8b11a75a5d1'}]}, 'public': True, 'created_at': '2022-02-02T14:23:30Z'}, {'id': '20038546464', 'type': 'IssueCommentEvent', 'actor': {'id': 1526295, 'login': 'sldblog', 'display_login': 'sldblog', 'gravatar_id': '', 'url': 'https://api.github.com/users/sldblog', 'avatar_url': 'https://avatars.githubusercontent.com/u/1526295?'}, 'repo': {'id': 312544484, 'name': 'ministryofjustice/hmpps-interventions-ui', 'url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui'}, 'payload': {'action': 'created', 'issue': {'url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/1197', 'repository_url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui', 'labels_url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/1197/labels{/name}', 'comments_url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/1197/comments', 'events_url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/1197/events', 'html_url': 'https://github.com/ministryofjustice/hmpps-interventions-ui/issues/1197', 'id': 1117364167, 'node_id': 'I_kwDOEqEM5M5CmZ_H', 'number': 1197, 'title': 'A branch protection setting is not enabled: Include administrators', 'user': {'login': 'AntonyBishop', 'id': 36888942, 'node_id': 'MDQ6VXNlcjM2ODg4OTQy', 'avatar_url': 'https://avatars.githubusercontent.com/u/36888942?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/AntonyBishop', 'html_url': 'https://github.com/AntonyBishop', 'followers_url': 'https://api.github.com/users/AntonyBishop/followers', 'following_url': 'https://api.github.com/users/AntonyBishop/following{/other_user}', 'gists_url': 'https://api.github.com/users/AntonyBishop/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/AntonyBishop/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/AntonyBishop/subscriptions', 'organizations_url': 'https://api.github.com/users/AntonyBishop/orgs', 'repos_url': 'https://api.github.com/users/AntonyBishop/repos', 'events_url': 'https://api.github.com/users/AntonyBishop/events{/privacy}', 'received_events_url': 'https://api.github.com/users/AntonyBishop/received_events', 'type': 'User', 'site_admin': False}, 'labels': [], 'state': 'closed', 'locked': False, 'assignee': None, 'assignees': [], 'milestone': None, 'comments': 1, 'created_at': '2022-01-28T12:45:33Z', 'updated_at': '2022-02-02T14:23:29Z', 'closed_at': '2022-02-02T14:23:29Z', 'author_association': 'NONE', 'active_lock_reason': None, 'body': 'Hi there\nThe default branch protection setting called Include administrators is not enabled for this repository\nSee repository settings/Branches/Branch protection rules\nEither add a new Branch protection rule or edit the existing branch protection rule and select the Include administrators option\nThis will enable the branch protection rules to admin uses as well\nSee the repository standards: https://github.com/ministryofjustice/github-repository-standards\nSee the report: https://operations-engineering-reports.cloud-platform.service.justice.gov.uk/github_repositories\nPlease contact Operations Engineering on Slack #ask-operations-engineering, if you need any assistance\n', 'reactions': {'url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/1197/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'timeline_url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/1197/timeline', 'performed_via_github_app': None}, 'comment': {'url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/comments/1027990260', 'html_url': 'https://github.com/ministryofjustice/hmpps-interventions-ui/issues/1197#issuecomment-1027990260', 'issue_url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/1197', 'id': 1027990260, 'node_id': 'IC_kwDOEqEM5M49ReL0', 'user': {'login': 'sldblog', 'id': 1526295, 'node_id': 'MDQ6VXNlcjE1MjYyOTU=', 'avatar_url': 'https://avatars.githubusercontent.com/u/1526295?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/sldblog', 'html_url': 'https://github.com/sldblog', 'followers_url': 'https://api.github.com/users/sldblog/followers', 'following_url': 'https://api.github.com/users/sldblog/following{/other_user}', 'gists_url': 'https://api.github.com/users/sldblog/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/sldblog/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/sldblog/subscriptions', 'organizations_url': 'https://api.github.com/users/sldblog/orgs', 'repos_url': 'https://api.github.com/users/sldblog/repos', 'events_url': 'https://api.github.com/users/sldblog/events{/privacy}', 'received_events_url': 'https://api.github.com/users/sldblog/received_events', 'type': 'User', 'site_admin': False}, 'created_at': '2022-02-02T14:23:29Z', 'updated_at': '2022-02-02T14:23:29Z', 'author_association': 'MEMBER', 'body': 'Done (feature/* branches)', 'reactions': {'url': 'https://api.github.com/repos/ministryofjustice/hmpps-interventions-ui/issues/comments/1027990260/reactions', 'total_count': 0, '+1': 0, '-1': 0, 'laugh': 0, 'hooray': 0, 'confused': 0, 'heart': 0, 'rocket': 0, 'eyes': 0}, 'performed_via_github_app': None}}, 'public': True, 'created_at': '2022-02-02T14:23:30Z', 'org': {'id': 2203574, 'login': 'ministryofjustice', 'gravatar_id': '', 'url': 'https://api.github.com/orgs/ministryofjustice', 'avatar_url': 'https://avatars.githubusercontent.com/u/2203574?'}}, {'id': '20038546609', 'type': 'PushEvent', 'actor': {'id': 43445963, 'login': 'paullaster', 'display_login': 'paullaster', 'gravatar_id': '', 'url': 'https://api.github.com/users/paullaster', 'avatar_url': 'https://avatars.githubusercontent.com/u/43445963?'}, 'repo': {'id': 454802080, 'name': 'paullaster/eclectics-ecommerce', 'url': 'https://api.github.com/repos/paullaster/eclectics-ecommerce'}, 'payload': {'push_id': 8993439093, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/master', 'head': '37eff08041baba364101159f50dd18b2f102b96d', 'before': 'c6a2880e0fb9b486c942b523ae5911e63dd72395', 'commits': [{'sha': '37eff08041baba364101159f50dd18b2f102b96d', 'author': {'email': 'paullasterokoth98@gmail.com', 'name': 'paullaster'}, 'message': 'Eclectics-ecommerce SPA initial commit', 'distinct': True, 'url': 'https://api.github.com/repos/paullaster/eclectics-ecommerce/commits/37eff08041baba364101159f50dd18b2f102b96d'}]}, 'public': True, 'created_at': '2022-02-02T14:23:31Z'}, {'id': '20038546607', 'type': 'PushEvent', 'actor': {'id': 92793982, 'login': 'natali177', 'display_login': 'natali177', 'gravatar_id': '', 'url': 'https://api.github.com/users/natali177', 'avatar_url': 'https://avatars.githubusercontent.com/u/92793982?'}, 'repo': {'id': 454686191, 'name': 'natali177/neoflex', 'url': 'https://api.github.com/repos/natali177/neoflex'}, 'payload': {'push_id': 8993439103, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/master', 'head': '78cb35bbad12f668d1eaa8379a6ffab89383c4ce', 'before': 'e655ff597cfdd2f54dae26695b30eb62c0f0d3a7', 'commits': [{'sha': '78cb35bbad12f668d1eaa8379a6ffab89383c4ce', 'author': {'email': 'nati_177@mail.ru', 'name': 'natali177'}, 'message': 'commit schema', 'distinct': True, 'url': 'https://api.github.com/repos/natali177/neoflex/commits/78cb35bbad12f668d1eaa8379a6ffab89383c4ce'}]}, 'public': True, 'created_at': '2022-02-02T14:23:31Z'}, {'id': '20038546441', 'type': 'PushEvent', 'actor': {'id': 3955124, 'login': 'Raicuparta', 'display_login': 'Raicuparta', 'gravatar_id': '', 'url': 'https://api.github.com/users/Raicuparta', 'avatar_url': 'https://avatars.githubusercontent.com/u/3955124?'}, 'repo': {'id': 435823157, 'name': 'Raicuparta/outerwildsmods.com', 'url': 'https://api.github.com/repos/Raicuparta/outerwildsmods.com'}, 'payload': {'push_id': 8993439128, 'size': 1, 'distinct_size': 1, 'ref': 'refs/heads/gh-pages', 'head': '7ca9f5f0c746629b25d6cc0a8846cbffafd2be5a', 'before': 'a6ff170e65bd0f68871cf0f95c472f1a1172d6ad', 'commits': [{'sha': '7ca9f5f0c746629b25d6cc0a8846cbffafd2be5a', 'author': {'email': 'Outer Wilds Mods Website', 'name': 'Outer Wilds Mods Website'}, 'message': 'Deploying to gh-pages from @ Raicuparta/outerwildsmods.com@e5734e6fa6761bd82f3fbfc9f8ac3ecf441ba5bd 🚀', 'distinct': True, 'url': 'https://api.github.com/repos/Raicuparta/outerwildsmods.com/commits/7ca9f5f0c746629b25d6cc0a8846cbffafd2be5a'}]}, 'public': True, 'created_at': '2022-02-02T14:23:30Z'}]
In [21]:
import pandas as pd
df = pd.DataFrame.from_dict(r.json())
df.groupby('type')['id'].count()
Out[21]:
type
CreateEvent                4
ForkEvent                  2
IssueCommentEvent          1
IssuesEvent                1
PullRequestEvent           1
PullRequestReviewEvent     2
PushEvent                 19
Name: id, dtype: int64

Exercice¶

  1. Add a new item in your navigation menu named Sentiment Classifier
  2. When the user select this item, a textbox is shown where our user can write a tweet and get its sentiment.

Bonus¶

Objectives of the day:

  • DATA APP
    • Live coding your ~first~ second (and third if we have time) complete data app:
      • Reproducing the NY Uber ride analysis
      • Creating a NLP as a service

References¶

  • Streamlit API references: https://docs.streamlit.io/library/api-reference
  • https://github.com/beingCurious/books#python
In [ ]:
df.columns
In [ ]:
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import wordpunct_tokenize
import pandas as pd
In [ ]:
df = pd.read_csv('../data/tweet-sentiment-withDay.csv')
In [ ]:
series_tweets = df['text']
tweet_str = series_tweets.str.cat(sep = ' ')
list_of_words = [i.lower() for i in wordpunct_tokenize(tweet_str) if i.lower() not in stop and i.isalpha()]
wordfreqdist = nltk.FreqDist(list_of_words)
mostcommon = wordfreqdist.most_common(30)
print(mostcommon)
In [ ]:
import pickle
from sklearn.ensemble import RandomForestRegressor
def train_model():
    paris_data = pd.read_csv('../data/ParisHousing.csv')
    feature_names = ['squareMeters', 'numberOfRooms', 'hasYard', 'hasPool', 'floors',
                'numPrevOwners', 'made', 'isNewBuilt', 'hasStormProtector',
                'basement', 'attic', 'garage', 'hasStorageRoom', 'hasGuestRoom']
    target_name = ['price']
    X = pd.DataFrame(paris_data, columns=feature_names)
    Y = pd.DataFrame(paris_data, columns=target_name)
    # Build Regression Model
    model = RandomForestRegressor()
    model.fit(X, Y.ravel())
    return model

price_model =train_model()
In [ ]:
filename = '../data/price_model.sav'
pickle.dump(price_model, open(filename, 'wb'))
In [ ]:
data_json = {"squareMeters":{"0":0.0},"numberOfRooms":{"0":1},"hasYard":{"0":False},"hasPool":{"0":False},"floors":{"0":1},"numPrevOwners":{"0":10},"made":{"0":2021.0},"isNewBuilt":{"0":False},"hasStormProtector":{"0":True},"basement":{"0":0.0},"attic":{"0":0.1},"garage":{"0":0.0},"hasStorageRoom":{"0":False},"hasGuestRoom":{"0":True}}
In [ ]:
df = pd.DataFrame(data=data_json)
In [ ]:
df.head()
In [ ]: